diff --git a/applications/external/arkanoid/application.fam b/applications/external/arkanoid/application.fam deleted file mode 100644 index 19e851514..000000000 --- a/applications/external/arkanoid/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="arkanoid", - name="Arkanoid", - apptype=FlipperAppType.EXTERNAL, - entry_point="arkanoid_game_app", - requires=["gui"], - stack_size=1 * 1024, - fap_icon="arkanoid_10px.png", - fap_category="Games", - fap_author="@xMasterX & @gotnull", - fap_version="1.0", - fap_description="Arkanoid Game", -) diff --git a/applications/external/arkanoid/arkanoid_10px.png b/applications/external/arkanoid/arkanoid_10px.png deleted file mode 100644 index 344d2db73..000000000 Binary files a/applications/external/arkanoid/arkanoid_10px.png and /dev/null differ diff --git a/applications/external/arkanoid/arkanoid_game.c b/applications/external/arkanoid/arkanoid_game.c deleted file mode 100644 index 2adf2e30b..000000000 --- a/applications/external/arkanoid/arkanoid_game.c +++ /dev/null @@ -1,479 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define TAG "Arkanoid" - -#define FLIPPER_LCD_WIDTH 128 -#define FLIPPER_LCD_HEIGHT 64 -#define MAX_SPEED 3 - -typedef enum { EventTypeTick, EventTypeKey } EventType; - -typedef struct { - //Brick Bounds used in collision detection - int leftBrick; - int rightBrick; - int topBrick; - int bottomBrick; - bool isHit[4][13]; //Array of if bricks are hit or not -} BrickState; - -typedef struct { - int dx; //Initial movement of ball - int dy; //Initial movement of ball - int xb; //Balls starting possition - int yb; //Balls starting possition - bool released; //If the ball has been released by the player - //Ball Bounds used in collision detection - int leftBall; - int rightBall; - int topBall; - int bottomBall; -} BallState; - -typedef struct { - FuriMutex* mutex; - BallState ball_state; - BrickState brick_state; - NotificationApp* notify; - unsigned int COLUMNS; //Columns of bricks - unsigned int ROWS; //Rows of bricks - bool initialDraw; //If the inital draw has happened - int xPaddle; //X position of paddle - char text[16]; //General string buffer - bool bounced; //Used to fix double bounce glitch - int lives; //Amount of lives - int level; //Current level - unsigned int score; //Score for the game - unsigned int brickCount; //Amount of bricks hit - int tick; //Tick counter - bool gameStarted; // Did the game start? - int speed; // Ball speed -} ArkanoidState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -static const NotificationSequence sequence_short_sound = { - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; - -// generate number in range [min,max) -int rand_range(int min, int max) { - return min + rand() % (max - min); -} - -void move_ball(Canvas* canvas, ArkanoidState* st) { - st->tick++; - - int current_speed = abs(st->speed - 1 - MAX_SPEED); - if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) { - return; - } - - if(st->ball_state.released) { - //Move ball - if(abs(st->ball_state.dx) == 2) { - st->ball_state.xb += st->ball_state.dx / 2; - // 2x speed is really 1.5 speed - if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2; - } else { - st->ball_state.xb += st->ball_state.dx; - } - st->ball_state.yb = st->ball_state.yb + st->ball_state.dy; - - //Set bounds - st->ball_state.leftBall = st->ball_state.xb; - st->ball_state.rightBall = st->ball_state.xb + 2; - st->ball_state.topBall = st->ball_state.yb; - st->ball_state.bottomBall = st->ball_state.yb + 2; - - //Bounce off top edge - if(st->ball_state.yb <= 0) { - st->ball_state.yb = 2; - st->ball_state.dy = -st->ball_state.dy; - } - - //Lose a life if bottom edge hit - if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) { - canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); - st->xPaddle = 54; - st->ball_state.yb = 60; - st->ball_state.released = false; - st->lives--; - st->gameStarted = false; - - if(rand_range(0, 2) == 0) { - st->ball_state.dx = 1; - } else { - st->ball_state.dx = -1; - } - } - - //Bounce off left side - if(st->ball_state.xb <= 0) { - st->ball_state.xb = 2; - st->ball_state.dx = -st->ball_state.dx; - } - - //Bounce off right side - if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) { - st->ball_state.xb = FLIPPER_LCD_WIDTH - 4; - st->ball_state.dx = -st->ball_state.dx; - // arduboy.tunes.tone(523, 250); - } - - //Bounce off paddle - if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 && - st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 && - st->ball_state.yb <= FLIPPER_LCD_HEIGHT) { - st->ball_state.dy = -st->ball_state.dy; - st->ball_state.dx = - ((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball - // prevent straight bounce, but not prevent roguuemaster from stealing - if(st->ball_state.dx == 0) { - st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1; - } - } - - //Bounce off Bricks - for(unsigned int row = 0; row < st->ROWS; row++) { - for(unsigned int column = 0; column < st->COLUMNS; column++) { - if(!st->brick_state.isHit[row][column]) { - //Sets Brick bounds - st->brick_state.leftBrick = 10 * column; - st->brick_state.rightBrick = 10 * column + 10; - st->brick_state.topBrick = 6 * row + 1; - st->brick_state.bottomBrick = 6 * row + 7; - - //If A collison has occured - if(st->ball_state.topBall <= st->brick_state.bottomBrick && - st->ball_state.bottomBall >= st->brick_state.topBrick && - st->ball_state.leftBall <= st->brick_state.rightBrick && - st->ball_state.rightBall >= st->brick_state.leftBrick) { - st->score += st->level; - // Blink led when we hit some brick - notification_message(st->notify, &sequence_short_sound); - //notification_message(st->notify, &sequence_blink_white_100); - - st->brickCount++; - st->brick_state.isHit[row][column] = true; - canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4); - - //Vertical collision - if(st->ball_state.bottomBall > st->brick_state.bottomBrick || - st->ball_state.topBall < st->brick_state.topBrick) { - //Only bounce once each ball move - if(!st->bounced) { - st->ball_state.dy = -st->ball_state.dy; - st->ball_state.yb += st->ball_state.dy; - st->bounced = true; - } - } - - //Hoizontal collision - if(st->ball_state.leftBall < st->brick_state.leftBrick || - st->ball_state.rightBall > st->brick_state.rightBrick) { - //Only bounce once brick each ball move - if(!st->bounced) { - st->ball_state.dx = -st->ball_state.dx; - st->ball_state.xb += st->ball_state.dx; - st->bounced = true; - } - } - } - } - } - } - - //Reset Bounce - st->bounced = false; - } else { - //Ball follows paddle - st->ball_state.xb = st->xPaddle + 5; - } -} - -void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) { - if(arkanoid_state->lives == 3) { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16); - } else if(arkanoid_state->lives == 2) { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12); - } else { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - } -} - -void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) { - snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score); - canvas_draw_str_aligned( - canvas, - FLIPPER_LCD_WIDTH - 2, - FLIPPER_LCD_HEIGHT - 6, - AlignRight, - AlignBottom, - arkanoid_state->text); -} - -void draw_ball(Canvas* canvas, ArkanoidState* ast) { - canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb); - canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb); - canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1); - canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1); - - move_ball(canvas, ast); -} - -void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) { - canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); -} - -void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) { - //Undraw paddle - canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); - - //Undraw ball - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1); - - //Alter various variables to reset the game - arkanoid_state->xPaddle = 54; - arkanoid_state->ball_state.yb = 60; - arkanoid_state->brickCount = 0; - arkanoid_state->ball_state.released = false; - arkanoid_state->gameStarted = false; - - // Reset all brick hit states - for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) { - for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) { - arkanoid_state->brick_state.isHit[row][column] = false; - } - } -} - -static void arkanoid_state_init(ArkanoidState* arkanoid_state) { - // Init notification - arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION); - - // Set the initial game state - arkanoid_state->COLUMNS = 13; - arkanoid_state->ROWS = 4; - arkanoid_state->ball_state.dx = -1; - arkanoid_state->ball_state.dy = -1; - arkanoid_state->speed = 2; - arkanoid_state->bounced = false; - arkanoid_state->lives = 3; - arkanoid_state->level = 1; - arkanoid_state->score = 0; - arkanoid_state->COLUMNS = 13; - arkanoid_state->COLUMNS = 13; - - // Reset initial state - arkanoid_state->initialDraw = false; - arkanoid_state->gameStarted = false; -} - -static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - ArkanoidState* arkanoid_state = ctx; - furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever); - - //Initial level draw - if(!arkanoid_state->initialDraw) { - arkanoid_state->initialDraw = true; - - // Set default font for text - canvas_set_font(canvas, FontSecondary); - - //Draws the new level - reset_level(canvas, arkanoid_state); - } - - //Draws new bricks and resets their values - for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) { - for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) { - if(!arkanoid_state->brick_state.isHit[row][column]) { - canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4); - } - } - } - - if(arkanoid_state->lives > 0) { - draw_paddle(canvas, arkanoid_state); - draw_ball(canvas, arkanoid_state); - draw_score(canvas, arkanoid_state); - draw_lives(canvas, arkanoid_state); - - if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) { - arkanoid_state->level++; - reset_level(canvas, arkanoid_state); - } - } else { - reset_level(canvas, arkanoid_state); - arkanoid_state->initialDraw = false; - arkanoid_state->lives = 3; - arkanoid_state->score = 0; - } - - furi_mutex_release(arkanoid_state->mutex); -} - -static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t arkanoid_game_app(void* p) { - UNUSED(p); - int32_t return_code = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState)); - arkanoid_state_init(arkanoid_state); - - arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!arkanoid_state->mutex) { - FURI_LOG_E(TAG, "Cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state); - view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // Key events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress || event.input.type == InputTypeLong || - event.input.type == InputTypeRepeat) { - switch(event.input.key) { - case InputKeyBack: - processing = false; - break; - case InputKeyRight: - if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) { - arkanoid_state->xPaddle += 8; - } - break; - case InputKeyLeft: - if(arkanoid_state->xPaddle > 0) { - arkanoid_state->xPaddle -= 8; - } - break; - case InputKeyUp: - if(arkanoid_state->speed < MAX_SPEED) { - arkanoid_state->speed++; - } - break; - case InputKeyDown: - if(arkanoid_state->speed > 1) { - arkanoid_state->speed--; - } - break; - case InputKeyOk: - if(arkanoid_state->gameStarted == false) { - //Release ball if FIRE pressed - arkanoid_state->ball_state.released = true; - - //Apply random direction to ball on release - if(rand_range(0, 2) == 0) { - arkanoid_state->ball_state.dx = 1; - } else { - arkanoid_state->ball_state.dx = -1; - } - - //Makes sure the ball heads upwards - arkanoid_state->ball_state.dy = -1; - //start the game flag - arkanoid_state->gameStarted = true; - } - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(arkanoid_state->mutex); - } - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - view_port_free(view_port); - furi_mutex_free(arkanoid_state->mutex); - -free_and_exit: - free(arkanoid_state); - furi_message_queue_free(event_queue); - - return return_code; -} diff --git a/applications/external/calculator/application.fam b/applications/external/calculator/application.fam deleted file mode 100644 index cfd183ec3..000000000 --- a/applications/external/calculator/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="calculator", - name="Calculator", - apptype=FlipperAppType.EXTERNAL, - entry_point="calculator_app", - cdefines=["APP_CALCULATOR"], - requires=["gui"], - stack_size=1 * 1024, - fap_icon="calcIcon.png", - fap_category="Tools", - fap_author="@n-o-T-I-n-s-a-n-e", - fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e", - fap_version="1.0", - fap_description="Calculator, that can calculate simple expressions", -) diff --git a/applications/external/calculator/calcIcon.png b/applications/external/calculator/calcIcon.png deleted file mode 100644 index 05cda6ce6..000000000 Binary files a/applications/external/calculator/calcIcon.png and /dev/null differ diff --git a/applications/external/calculator/calculator.c b/applications/external/calculator/calculator.c deleted file mode 100644 index cc12cb7d1..000000000 --- a/applications/external/calculator/calculator.c +++ /dev/null @@ -1,458 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // Header-file for boolean data-type. -#include // Header-file for string functions. -#include "tinyexpr.h" // Header-file for the TinyExpr library. - -#include -#include - -const short MAX_TEXT_LENGTH = 20; - -typedef struct { - short x; - short y; -} selectedPosition; - -typedef struct { - FuriMutex* mutex; - selectedPosition position; - //string with the inputted calculator text - char text[20]; - short textLength; - char log[20]; -} Calculator; - -char getKeyAtPosition(short x, short y) { - if(x == 0 && y == 0) { - return 'C'; - } - if(x == 1 && y == 0) { - return '<'; - } - if(x == 2 && y == 0) { - return '%'; - } - if(x == 3 && y == 0) { - return '/'; - } - if(x == 0 && y == 1) { - return '1'; - } - if(x == 1 && y == 1) { - return '2'; - } - if(x == 2 && y == 1) { - return '3'; - } - if(x == 3 && y == 1) { - return '*'; - } - if(x == 0 && y == 2) { - return '4'; - } - if(x == 1 && y == 2) { - return '5'; - } - if(x == 2 && y == 2) { - return '6'; - } - if(x == 3 && y == 2) { - return '-'; - } - if(x == 0 && y == 3) { - return '7'; - } - if(x == 1 && y == 3) { - return '8'; - } - if(x == 2 && y == 3) { - return '9'; - } - if(x == 3 && y == 3) { - return '+'; - } - if(x == 0 && y == 4) { - return '('; - } - if(x == 1 && y == 4) { - return '0'; - } - if(x == 2 && y == 4) { - return '.'; - } - if(x == 3 && y == 4) { - return '='; - } - return ' '; -} - -short calculateStringWidth(const char* str, short lenght) { - /* widths: - 1 = 2 - 2, 3, 4, 5, 6, 7, 8, 9, 0, X, -, +, . = = 5 - %, / = 7 - S = 5 - (, ) = 3 - - */ - short width = 0; - for(short i = 0; i < lenght; i++) { - switch(str[i]) { - case '1': - width += 2; - break; - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - case '*': - case '-': - case '+': - case '.': - width += 5; - break; - case '%': - case '/': - width += 7; - break; - case 'S': - width += 5; - break; - case '(': - case ')': - width += 3; - break; - default: - break; - } - width += 1; - } - - return width; -} - -void generate_calculator_layout(Canvas* canvas) { - //draw dotted lines - for(int i = 0; i <= 64; i++) { - if(i % 2 == 0) { - canvas_draw_dot(canvas, i, 14); - canvas_draw_dot(canvas, i, 33); - } - if(i % 2 == 1) { - canvas_draw_dot(canvas, i, 15); - canvas_draw_dot(canvas, i, 34); - } - } - - //draw horizontal lines - canvas_draw_box(canvas, 0, 41, 64, 2); - canvas_draw_box(canvas, 0, 57, 64, 2); - canvas_draw_box(canvas, 0, 73, 64, 2); - canvas_draw_box(canvas, 0, 89, 64, 2); - canvas_draw_box(canvas, 0, 105, 64, 2); - canvas_draw_box(canvas, 0, 121, 64, 2); - - //draw vertical lines - canvas_draw_box(canvas, 0, 43, 1, 80); - canvas_draw_box(canvas, 15, 43, 2, 80); - canvas_draw_box(canvas, 31, 43, 2, 80); - canvas_draw_box(canvas, 47, 43, 2, 80); - canvas_draw_box(canvas, 63, 43, 1, 80); - - //draw buttons - //row 1 (C, ;, %, ÷) - canvas_draw_str(canvas, 5, 54, "C"); - canvas_draw_str(canvas, 19, 54, " <-"); - canvas_draw_str(canvas, 35, 54, " %"); - canvas_draw_str(canvas, 51, 54, " /"); - - //row 2 (1, 2, 3, X) - canvas_draw_str(canvas, 5, 70, " 1"); - canvas_draw_str(canvas, 19, 70, " 2"); - canvas_draw_str(canvas, 35, 70, " 3"); - canvas_draw_str(canvas, 51, 70, " X"); - - //row 3 (4, 5, 6, -) - canvas_draw_str(canvas, 5, 86, " 4"); - canvas_draw_str(canvas, 19, 86, " 5"); - canvas_draw_str(canvas, 35, 86, " 6"); - canvas_draw_str(canvas, 51, 86, " -"); - - //row 4 (7, 8, 9, +) - canvas_draw_str(canvas, 5, 102, " 7"); - canvas_draw_str(canvas, 19, 102, " 8"); - canvas_draw_str(canvas, 35, 102, " 9"); - canvas_draw_str(canvas, 51, 102, " +"); - - //row 5 (+/-, 0, ., =) - canvas_draw_str(canvas, 3, 118, "( )"); - canvas_draw_str(canvas, 19, 118, " 0"); - canvas_draw_str(canvas, 35, 118, " ."); - canvas_draw_str(canvas, 51, 118, " ="); -} - -void calculator_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const Calculator* calculator_state = ctx; - furi_mutex_acquire(calculator_state->mutex, FuriWaitForever); - - canvas_clear(canvas); - - //show selected button - short startX = 1; - short startY = 43; - - canvas_set_color(canvas, ColorBlack); - canvas_draw_box( - canvas, - startX + (calculator_state->position.x) * 16, - (startY) + (calculator_state->position.y) * 16, - 16, - 16); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box( - canvas, - startX + (calculator_state->position.x) * 16 + 2, - (startY) + (calculator_state->position.y) * 16 + 2, - 10, - 10); - - canvas_set_color(canvas, ColorBlack); - generate_calculator_layout(canvas); - - //draw text - short stringWidth = calculateStringWidth(calculator_state->text, calculator_state->textLength); - short startingPosition = 5; - if(stringWidth > 60) { - startingPosition += 60 - (stringWidth + 5); - } - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, startingPosition, 28, calculator_state->text); - //canvas_draw_str(canvas, 10, 10, calculator_state->log); - - //draw cursor - canvas_draw_box(canvas, stringWidth + 5, 29, 5, 1); - - furi_mutex_release(calculator_state->mutex); -} - -void calculator_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -void calculate(Calculator* calculator_state) { - double result; - result = te_interp(calculator_state->text, 0); - - calculator_state->textLength = 0; - calculator_state->text[0] = '\0'; - // sprintf(calculator_state->text, "%f", result); - - //invert sign if negative - if(result < 0) { - calculator_state->text[calculator_state->textLength++] = '-'; - result = -result; - } - - //get numbers before and after decimal - int beforeDecimal = result; - int afterDecimal = (result - beforeDecimal) * 100; - - char beforeDecimalString[10]; - char afterDecimalString[10]; - int i = 0; - //parse to a string - while(beforeDecimal > 0) { - beforeDecimalString[i++] = beforeDecimal % 10 + '0'; - beforeDecimal /= 10; - } - // invert string - for(int j = 0; j < i / 2; j++) { - char temp = beforeDecimalString[j]; - beforeDecimalString[j] = beforeDecimalString[i - j - 1]; - beforeDecimalString[i - j - 1] = temp; - } - //add it to the answer - for(int j = 0; j < i; j++) { - calculator_state->text[calculator_state->textLength++] = beforeDecimalString[j]; - } - - i = 0; - if(afterDecimal > 0) { - while(afterDecimal > 0) { - afterDecimalString[i++] = afterDecimal % 10 + '0'; - afterDecimal /= 10; - } - // invert string - for(int j = 0; j < i / 2; j++) { - char temp = afterDecimalString[j]; - afterDecimalString[j] = afterDecimalString[i - j - 1]; - afterDecimalString[i - j - 1] = temp; - } - - //add decimal point - calculator_state->text[calculator_state->textLength++] = '.'; - - //add numbers after decimal - for(int j = 0; j < i; j++) { - calculator_state->text[calculator_state->textLength++] = afterDecimalString[j]; - } - } - calculator_state->text[calculator_state->textLength] = '\0'; -} - -int32_t calculator_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - Calculator* calculator_state = malloc(sizeof(Calculator)); - calculator_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!calculator_state->mutex) { - //FURI_LOG_E("calculator", "cannot create mutex\r\n"); - free(calculator_state); - return -1; - } - - // Configure view port - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, calculator_draw_callback, calculator_state); - view_port_input_callback_set(view_port, calculator_input_callback, event_queue); - view_port_set_orientation(view_port, ViewPortOrientationVertical); - - // Register view port in GUI - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - //NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - InputEvent event; - - while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - //break out of the loop if the back key is pressed - if(event.type == InputTypeShort && event.key == InputKeyBack) { - break; - } - - if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyUp: - if(calculator_state->position.y > 0) { - calculator_state->position.y--; - } - break; - case InputKeyDown: - if(calculator_state->position.y < 4) { - calculator_state->position.y++; - } - break; - case InputKeyLeft: - if(calculator_state->position.x > 0) { - calculator_state->position.x--; - } - break; - case InputKeyRight: - if(calculator_state->position.x < 3) { - calculator_state->position.x++; - } - break; - case InputKeyOk: { - //add the selected button to the text - //char* text = calculator_state->text; - // short* textLength = &calculator_state->textLength; - - char key = - getKeyAtPosition(calculator_state->position.x, calculator_state->position.y); - - switch(key) { - case 'C': - while(calculator_state->textLength > 0) { - calculator_state->text[calculator_state->textLength--] = '\0'; - } - calculator_state->text[0] = '\0'; - calculator_state->log[2] = key; - break; - case '<': - calculator_state->log[2] = key; - if(calculator_state->textLength > 0) { - calculator_state->text[--calculator_state->textLength] = '\0'; - } else { - calculator_state->text[0] = '\0'; - } - break; - case '=': - calculator_state->log[2] = key; - calculate(calculator_state); - break; - case '%': - case '/': - case '*': - case '-': - case '+': - case '.': - case '(': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - if(calculator_state->textLength < MAX_TEXT_LENGTH) { - calculator_state->text[calculator_state->textLength++] = key; - calculator_state->text[calculator_state->textLength] = '\0'; - } - //calculator_state->log[1] = calculator_state->text[*textLength]; - break; - default: - break; - } - } - default: - break; - } - - view_port_update(view_port); - } - - if(event.type == InputTypeLong) { - switch(event.key) { - case InputKeyOk: - if(calculator_state->position.x == 0 && calculator_state->position.y == 4) { - if(calculator_state->textLength < MAX_TEXT_LENGTH) { - calculator_state->text[calculator_state->textLength++] = ')'; - calculator_state->text[calculator_state->textLength] = '\0'; - } - view_port_update(view_port); - } - break; - default: - break; - } - } - } - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_mutex_free(calculator_state->mutex); - furi_message_queue_free(event_queue); - - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - free(calculator_state); - - return 0; -} diff --git a/applications/external/calculator/tinyexpr.c b/applications/external/calculator/tinyexpr.c deleted file mode 100644 index cfd4cb8ab..000000000 --- a/applications/external/calculator/tinyexpr.c +++ /dev/null @@ -1,786 +0,0 @@ -// SPDX-License-Identifier: Zlib -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2020 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -/* COMPILE TIME OPTIONS */ - -/* Exponentiation associativity: -For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. -For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ -/* #define TE_POW_FROM_RIGHT */ - -/* Logarithms -For log = base 10 log do nothing -For log = natural log uncomment the next line. */ -/* #define TE_NAT_LOG */ - -#include "tinyexpr.h" -#include -#include -#include -#include -#include -#include - -#ifndef NAN -#define NAN (0.0 / 0.0) -#endif - -#ifndef INFINITY -#define INFINITY (1.0 / 0.0) -#endif - -typedef double (*te_fun2)(double, double); - -enum { - TOK_NULL = TE_CLOSURE7 + 1, - TOK_ERROR, - TOK_END, - TOK_SEP, - TOK_OPEN, - TOK_CLOSE, - TOK_NUMBER, - TOK_VARIABLE, - TOK_INFIX -}; - -enum { TE_CONSTANT = 1 }; - -typedef struct state { - const char* start; - const char* next; - int type; - union { - double value; - const double* bound; - const void* function; - }; - void* context; - - const te_variable* lookup; - int lookup_len; -} state; - -#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F) - -#define IS_PURE(TYPE) (((TYPE)&TE_FLAG_PURE) != 0) -#define IS_FUNCTION(TYPE) (((TYPE)&TE_FUNCTION0) != 0) -#define IS_CLOSURE(TYPE) (((TYPE)&TE_CLOSURE0) != 0) -#define ARITY(TYPE) (((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE)&0x00000007) : 0) -#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__}) - -static te_expr* new_expr(const int type, const te_expr* parameters[]) { - const int arity = ARITY(type); - const int psize = sizeof(void*) * arity; - const int size = - (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0); - te_expr* ret = malloc(size); - memset(ret, 0, size); - if(arity && parameters) { - memcpy(ret->parameters, parameters, psize); - } - ret->type = type; - ret->bound = 0; - return ret; -} - -void te_free_parameters(te_expr* n) { - if(!n) return; - switch(TYPE_MASK(n->type)) { - case TE_FUNCTION7: - case TE_CLOSURE7: - te_free(n->parameters[6]); /* Falls through. */ - case TE_FUNCTION6: - case TE_CLOSURE6: - te_free(n->parameters[5]); /* Falls through. */ - case TE_FUNCTION5: - case TE_CLOSURE5: - te_free(n->parameters[4]); /* Falls through. */ - case TE_FUNCTION4: - case TE_CLOSURE4: - te_free(n->parameters[3]); /* Falls through. */ - case TE_FUNCTION3: - case TE_CLOSURE3: - te_free(n->parameters[2]); /* Falls through. */ - case TE_FUNCTION2: - case TE_CLOSURE2: - te_free(n->parameters[1]); /* Falls through. */ - case TE_FUNCTION1: - case TE_CLOSURE1: - te_free(n->parameters[0]); - } -} - -void te_free(te_expr* n) { - if(!n) return; - te_free_parameters(n); - free(n); -} - -static double pi(void) { - return 3.14159265358979323846; -} -static double e(void) { - return 2.71828182845904523536; -} -static double fac(double a) { /* simplest version of fac */ - if(a < (double)0.0) return NAN; - if(a > UINT_MAX) return INFINITY; - unsigned int ua = (unsigned int)(a); - unsigned long int result = 1, i; - for(i = 1; i <= ua; i++) { - if(i > ULONG_MAX / result) return INFINITY; - result *= i; - } - return (double)result; -} -static double ncr(double n, double r) { - if(n < (double)0.0 || r < (double)0.0 || n < r) return NAN; - if(n > UINT_MAX || r > UINT_MAX) return INFINITY; - unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i; - unsigned long int result = 1; - if(ur > un / 2) ur = un - ur; - for(i = 1; i <= ur; i++) { - if(result > ULONG_MAX / (un - ur + i)) return INFINITY; - result *= un - ur + i; - result /= i; - } - return result; -} -static double npr(double n, double r) { - return ncr(n, r) * fac(r); -} - -#ifdef _MSC_VER -#pragma function(ceil) -#pragma function(floor) -#endif - -static const te_variable functions[] = { - /* must be in alphabetical order */ - {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0}, - {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#ifdef TE_NAT_LOG - {"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#else - {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#endif - {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0}, - {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {0, 0, 0, 0}}; - -static const te_variable* find_builtin(const char* name, int len) { - int imin = 0; - int imax = sizeof(functions) / sizeof(te_variable) - 2; - - /*Binary search.*/ - while(imax >= imin) { - const int i = (imin + ((imax - imin) / 2)); - int c = strncmp(name, functions[i].name, len); - if(!c) c = '\0' - functions[i].name[len]; - if(c == 0) { - return functions + i; - } else if(c > 0) { - imin = i + 1; - } else { - imax = i - 1; - } - } - - return 0; -} - -static const te_variable* find_lookup(const state* s, const char* name, int len) { - int iters; - const te_variable* var; - if(!s->lookup) return 0; - - for(var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) { - if(strncmp(name, var->name, len) == 0 && var->name[len] == '\0') { - return var; - } - } - return 0; -} - -static double add(double a, double b) { - return a + b; -} -static double sub(double a, double b) { - return a - b; -} -static double mul(double a, double b) { - return a * b; -} -static double divide(double a, double b) { - return a / b; -} -static double negate(double a) { - return -a; -} -static double comma(double a, double b) { - (void)a; - return b; -} - -void next_token(state* s) { - s->type = TOK_NULL; - - do { - if(!*s->next) { - s->type = TOK_END; - return; - } - - /* Try reading a number. */ - if((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') { - s->value = strtof(s->next, (char**)&s->next); - s->type = TOK_NUMBER; - } else { - /* Look for a variable or builtin function call. */ - if(isalpha((int)s->next[0])) { - const char* start; - start = s->next; - while(isalpha((int)s->next[0]) || isdigit((int)s->next[0]) || (s->next[0] == '_')) - s->next++; - - const te_variable* var = find_lookup(s, start, s->next - start); - if(!var) var = find_builtin(start, s->next - start); - - if(!var) { - s->type = TOK_ERROR; - } else { - switch(TYPE_MASK(var->type)) { - case TE_VARIABLE: - s->type = TOK_VARIABLE; - s->bound = var->address; - break; - - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: /* Falls through. */ - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: /* Falls through. */ - s->context = var->context; /* Falls through. */ - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: /* Falls through. */ - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: /* Falls through. */ - s->type = var->type; - s->function = var->address; - break; - } - } - - } else { - /* Look for an operator or special character. */ - switch(s->next++[0]) { - case '+': - s->type = TOK_INFIX; - s->function = add; - break; - case '-': - s->type = TOK_INFIX; - s->function = sub; - break; - case '*': - s->type = TOK_INFIX; - s->function = mul; - break; - case '/': - s->type = TOK_INFIX; - s->function = divide; - break; - case '^': - s->type = TOK_INFIX; - s->function = pow; - break; - case '%': - s->type = TOK_INFIX; - s->function = fmod; - break; - case '(': - s->type = TOK_OPEN; - break; - case ')': - s->type = TOK_CLOSE; - break; - case ',': - s->type = TOK_SEP; - break; - case ' ': - case '\t': - case '\n': - case '\r': - break; - default: - s->type = TOK_ERROR; - break; - } - } - } - } while(s->type == TOK_NULL); -} - -static te_expr* list(state* s); -static te_expr* expr(state* s); -static te_expr* power(state* s); - -static te_expr* base(state* s) { - /* = | | {"(" ")"} | | "(" {"," } ")" | "(" ")" */ - te_expr* ret; - int arity; - - switch(TYPE_MASK(s->type)) { - case TOK_NUMBER: - ret = new_expr(TE_CONSTANT, 0); - ret->value = s->value; - next_token(s); - break; - - case TOK_VARIABLE: - ret = new_expr(TE_VARIABLE, 0); - ret->bound = s->bound; - next_token(s); - break; - - case TE_FUNCTION0: - case TE_CLOSURE0: - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[0] = s->context; - next_token(s); - if(s->type == TOK_OPEN) { - next_token(s); - if(s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - break; - - case TE_FUNCTION1: - case TE_CLOSURE1: - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[1] = s->context; - next_token(s); - ret->parameters[0] = power(s); - break; - - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - arity = ARITY(s->type); - - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[arity] = s->context; - next_token(s); - - if(s->type != TOK_OPEN) { - s->type = TOK_ERROR; - } else { - int i; - for(i = 0; i < arity; i++) { - next_token(s); - ret->parameters[i] = expr(s); - if(s->type != TOK_SEP) { - break; - } - } - if(s->type != TOK_CLOSE || i != arity - 1) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - - break; - - case TOK_OPEN: - next_token(s); - ret = list(s); - if(s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - break; - - default: - ret = new_expr(0, 0); - s->type = TOK_ERROR; - ret->value = NAN; - break; - } - - return ret; -} - -static te_expr* power(state* s) { - /* = {("-" | "+")} */ - int sign = 1; - while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) { - if(s->function == sub) sign = -sign; - next_token(s); - } - - te_expr* ret; - - if(sign == 1) { - ret = base(s); - } else { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); - ret->function = negate; - } - - return ret; -} - -#ifdef TE_POW_FROM_RIGHT -static te_expr* factor(state* s) { - /* = {"^" } */ - te_expr* ret = power(s); - - int neg = 0; - - if(ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { - te_expr* se = ret->parameters[0]; - free(ret); - ret = se; - neg = 1; - } - - te_expr* insertion = 0; - - while(s->type == TOK_INFIX && (s->function == pow)) { - te_fun2 t = s->function; - next_token(s); - - if(insertion) { - /* Make exponentiation go right-to-left. */ - te_expr* insert = - NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s)); - insert->function = t; - insertion->parameters[1] = insert; - insertion = insert; - } else { - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->function = t; - insertion = ret; - } - } - - if(neg) { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); - ret->function = negate; - } - - return ret; -} -#else -static te_expr* factor(state* s) { - /* = {"^" } */ - te_expr* ret = power(s); - - while(s->type == TOK_INFIX && (s->function == pow)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->function = t; - } - - return ret; -} -#endif - -static te_expr* term(state* s) { - /* = {("*" | "/" | "%") } */ - te_expr* ret = factor(s); - - while(s->type == TOK_INFIX && - (s->function == mul || s->function == divide || s->function == fmod)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s)); - ret->function = t; - } - - return ret; -} - -static te_expr* expr(state* s) { - /* = {("+" | "-") } */ - te_expr* ret = term(s); - - while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s)); - ret->function = t; - } - - return ret; -} - -static te_expr* list(state* s) { - /* = {"," } */ - te_expr* ret = expr(s); - - while(s->type == TOK_SEP) { - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s)); - ret->function = comma; - } - - return ret; -} - -#define TE_FUN(...) ((double (*)(__VA_ARGS__))n->function) -#define M(e) te_eval(n->parameters[e]) - -double te_eval(const te_expr* n) { - if(!n) return NAN; - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: - return n->value; - case TE_VARIABLE: - return *n->bound; - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - switch(ARITY(n->type)) { - case 0: - return TE_FUN(void)(); - case 1: - return TE_FUN(double)(M(0)); - case 2: - return TE_FUN(double, double)(M(0), M(1)); - case 3: - return TE_FUN(double, double, double)(M(0), M(1), M(2)); - case 4: - return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3)); - case 5: - return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4)); - case 6: - return TE_FUN(double, double, double, double, double, double)( - M(0), M(1), M(2), M(3), M(4), M(5)); - case 7: - return TE_FUN(double, double, double, double, double, double, double)( - M(0), M(1), M(2), M(3), M(4), M(5), M(6)); - default: - return NAN; - } - - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - switch(ARITY(n->type)) { - case 0: - return TE_FUN(void*)(n->parameters[0]); - case 1: - return TE_FUN(void*, double)(n->parameters[1], M(0)); - case 2: - return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1)); - case 3: - return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2)); - case 4: - return TE_FUN(void*, double, double, double, double)( - n->parameters[4], M(0), M(1), M(2), M(3)); - case 5: - return TE_FUN(void*, double, double, double, double, double)( - n->parameters[5], M(0), M(1), M(2), M(3), M(4)); - case 6: - return TE_FUN(void*, double, double, double, double, double, double)( - n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5)); - case 7: - return TE_FUN(void*, double, double, double, double, double, double, double)( - n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6)); - default: - return NAN; - } - - default: - return NAN; - } -} - -#undef TE_FUN -#undef M - -static void optimize(te_expr* n) { - /* Evaluates as much as possible. */ - if(n->type == TE_CONSTANT) return; - if(n->type == TE_VARIABLE) return; - - /* Only optimize out functions flagged as pure. */ - if(IS_PURE(n->type)) { - const int arity = ARITY(n->type); - int known = 1; - int i; - for(i = 0; i < arity; ++i) { - optimize(n->parameters[i]); - if(((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) { - known = 0; - } - } - if(known) { - const double value = te_eval(n); - te_free_parameters(n); - n->type = TE_CONSTANT; - n->value = value; - } - } -} - -te_expr* - te_compile(const char* expression, const te_variable* variables, int var_count, int* error) { - state s; - s.start = s.next = expression; - s.lookup = variables; - s.lookup_len = var_count; - - next_token(&s); - te_expr* root = list(&s); - - if(s.type != TOK_END) { - te_free(root); - if(error) { - *error = (s.next - s.start); - if(*error == 0) *error = 1; - } - return 0; - } else { - optimize(root); - if(error) *error = 0; - return root; - } -} - -double te_interp(const char* expression, int* error) { - te_expr* n = te_compile(expression, 0, 0, error); - double ret; - if(n) { - ret = te_eval(n); - te_free(n); - } else { - ret = NAN; - } - return ret; -} - -static void pn(const te_expr* n, int depth) { - int i, arity; - printf("%*s", depth, ""); - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: - printf("%f\n", n->value); - break; - case TE_VARIABLE: - printf("bound %p\n", n->bound); - break; - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - arity = ARITY(n->type); - printf("f%d", arity); - for(i = 0; i < arity; i++) { - printf(" %p", n->parameters[i]); - } - printf("\n"); - for(i = 0; i < arity; i++) { - pn(n->parameters[i], depth + 1); - } - break; - } -} - -void te_print(const te_expr* n) { - pn(n, 0); -} diff --git a/applications/external/calculator/tinyexpr.h b/applications/external/calculator/tinyexpr.h deleted file mode 100644 index 3833965a1..000000000 --- a/applications/external/calculator/tinyexpr.h +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: Zlib -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2020 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef TINYEXPR_H -#define TINYEXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct te_expr { - int type; - union { - double value; - const double* bound; - const void* function; - }; - void* parameters[1]; -} te_expr; - -enum { - TE_VARIABLE = 0, - - TE_FUNCTION0 = 8, - TE_FUNCTION1, - TE_FUNCTION2, - TE_FUNCTION3, - TE_FUNCTION4, - TE_FUNCTION5, - TE_FUNCTION6, - TE_FUNCTION7, - - TE_CLOSURE0 = 16, - TE_CLOSURE1, - TE_CLOSURE2, - TE_CLOSURE3, - TE_CLOSURE4, - TE_CLOSURE5, - TE_CLOSURE6, - TE_CLOSURE7, - - TE_FLAG_PURE = 32 -}; - -typedef struct te_variable { - const char* name; - const void* address; - int type; - void* context; -} te_variable; - -/* Parses the input expression, evaluates it, and frees it. */ -/* Returns NaN on error. */ -double te_interp(const char* expression, int* error); - -/* Parses the input expression and binds variables. */ -/* Returns NULL on error. */ -te_expr* - te_compile(const char* expression, const te_variable* variables, int var_count, int* error); - -/* Evaluates the expression. */ -double te_eval(const te_expr* n); - -/* Prints debugging information on the syntax tree. */ -void te_print(const te_expr* n); - -/* Frees the expression. */ -/* This is safe to call on NULL pointers. */ -void te_free(te_expr* n); - -#ifdef __cplusplus -} -#endif - -#endif /*TINYEXPR_H*/ diff --git a/applications/external/doom/application.fam b/applications/external/doom/application.fam deleted file mode 100644 index 995286d74..000000000 --- a/applications/external/doom/application.fam +++ /dev/null @@ -1,17 +0,0 @@ -App( - appid="doom", - name="DOOM", - apptype=FlipperAppType.EXTERNAL, - entry_point="doom_app", - requires=[ - "gui", - "music_player", - ], - stack_size=4 * 1024, - fap_icon="doom_10px.png", - fap_category="Games", - fap_icon_assets="assets", - fap_author="@xMasterX & @Svarich & @hedger (original code by @p4nic4ttack)", - fap_version="1.0", - fap_description="Will it run Doom?", -) diff --git a/applications/external/doom/assets.c b/applications/external/doom/assets.c deleted file mode 100644 index 864588581..000000000 --- a/applications/external/doom/assets.c +++ /dev/null @@ -1,331 +0,0 @@ -#include "assets.h" - -const uint8_t space[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t zero[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60}; -const uint8_t one[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x70}; -const uint8_t two[] = {0x00, 0x60, 0x90, 0x20, 0x40, 0xf0}; -const uint8_t three[] = {0x00, 0x60, 0x90, 0x20, 0x90, 0x60}; -const uint8_t four[] = {0x00, 0x90, 0x90, 0xf0, 0x10, 0x10}; -const uint8_t five[] = {0x00, 0xf0, 0x80, 0xe0, 0x10, 0xe0}; -const uint8_t six[] = {0x00, 0x60, 0x80, 0xe0, 0x90, 0x60}; -const uint8_t seven[] = {0x00, 0xf0, 0x10, 0x10, 0x10, 0x10}; -const uint8_t eight[] = {0x00, 0x60, 0x90, 0x60, 0x90, 0x60}; -const uint8_t nine[] = {0x00, 0x60, 0x90, 0x70, 0x10, 0x60}; -const uint8_t A[] = {0x00, 0x60, 0x90, 0xf0, 0x90, 0x90}; -const uint8_t B[] = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0xe0}; -const uint8_t C[] = {0x00, 0x60, 0x90, 0x80, 0x90, 0x60}; -const uint8_t D[] = {0x00, 0xe0, 0x90, 0x90, 0x90, 0xe0}; -const uint8_t E[] = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0xf0}; -const uint8_t F[] = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80}; -const uint8_t G[] = {0x00, 0x60, 0x80, 0x80, 0x90, 0x60}; -const uint8_t H[] = {0x00, 0x90, 0x90, 0xf0, 0x90, 0x90}; -const uint8_t I[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x20}; -const uint8_t J[] = {0x00, 0x10, 0x10, 0x10, 0x90, 0x60}; -const uint8_t K[] = {0x00, 0x90, 0xa0, 0xc0, 0xa0, 0x90}; -const uint8_t L[] = {0x00, 0x80, 0x80, 0x80, 0x80, 0xf0}; -const uint8_t M[] = {0x00, 0x90, 0xf0, 0x90, 0x90, 0x90}; -const uint8_t N[] = {0x00, 0x90, 0xd0, 0xb0, 0x90, 0x90}; -const uint8_t O[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60}; -const uint8_t P[] = {0x00, 0xe0, 0x90, 0xe0, 0x80, 0x80}; -const uint8_t Q[] = {0x00, 0x60, 0x90, 0x90, 0xb0, 0x70}; -const uint8_t R[] = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0x90}; -const uint8_t S[] = {0x00, 0x60, 0x80, 0x60, 0x10, 0xe0}; -const uint8_t T[] = {0x00, 0xe0, 0x40, 0x40, 0x40, 0x40}; -const uint8_t U[] = {0x00, 0x90, 0x90, 0x90, 0x90, 0x60}; -const uint8_t V[] = {0x00, 0x90, 0x90, 0x90, 0x60, 0x60}; -const uint8_t W[] = {0x00, 0x90, 0x90, 0x90, 0xf0, 0x90}; -const uint8_t X[] = {0x00, 0x90, 0x90, 0x60, 0x90, 0x90}; -const uint8_t Y[] = {0x00, 0x90, 0x90, 0x60, 0x60, 0x60}; -const uint8_t Z[] = {0x00, 0xf0, 0x10, 0x60, 0x80, 0xf0}; -const uint8_t dot[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x40}; -const uint8_t comma[] = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40}; -const uint8_t dash[] = {0x00, 0x00, 0x00, 0x60, 0x00, 0x00}; -const uint8_t underscore[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0xf0}; -const uint8_t bracket_open[] = {0x00, 0x20, 0x40, 0x40, 0x40, 0x20}; -const uint8_t bracket_close[] = {0x00, 0x40, 0x20, 0x20, 0x20, 0x40}; -const uint8_t cross_left[] = {0x10, 0x10, 0x70, 0x70, 0x10, 0x10}; -const uint8_t cross_right[] = {0x80, 0x80, 0xe0, 0xe0, 0x80, 0x80}; -const uint8_t pacman_left[] = {0x00, 0x30, 0x50, 0x70, 0x70, 0x00}; -const uint8_t pacman_right[] = {0x00, 0xc0, 0x60, 0xe0, 0xe0, 0xe0}; -const uint8_t box[] = {0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00}; -const uint8_t* char_arr[48] = { - space, - zero, - one, - two, - three, - four, - five, - six, - seven, - eight, - nine, - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - dot, - comma, - dash, - underscore, - bracket_open, - bracket_close, - cross_left, - cross_right, - pacman_left, - pacman_right, - box}; -const uint8_t gradient[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x22, 0x22, - 0x00, 0x00, 0x8a, 0x8a, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0xaa, 0xaa, - 0x10, 0x10, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x01, 0x01, 0xaa, 0xaa, - 0x44, 0x44, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x44, 0x44, 0xaa, 0xaa, - 0x15, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xbb, 0xbb, - 0x55, 0x55, 0xaa, 0xea, 0x55, 0x55, 0xbb, 0xbb, 0x55, 0x55, 0xff, 0xff, - 0x55, 0x55, 0xfb, 0xfb, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xbb, 0xbf, - 0x57, 0x57, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0x77, 0x75, 0xff, 0xff, - 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -//const uint8_t gun[] = {0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x27, 0xff, 0xff, 0xfe, 0x3b, 0xff, 0xff, 0xfd, 0xfb, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xfd, 0x15, 0xff, 0xff, 0xfb, 0x2e, 0xff, 0xff, 0xf6, 0x77, 0x7f, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xf2, 0x3d, 0x7f, 0xff, 0xd6, 0x7e, 0x3f, 0xff, 0xf4, 0x5d, 0xdf, 0xff, 0xce, 0xbf, 0xbf, 0xff, 0xdc, 0xff, 0x3f, 0xff, 0xec, 0xff, 0xbf, 0xff, 0x8d, 0xfd, 0xff, 0xff, 0xb6, 0xff, 0xbf, 0xfe, 0x1f, 0x57, 0xdf, 0xf8, 0x0e, 0xff, 0xcf, 0xf4, 0x46, 0x1f, 0x17, 0xf8, 0xa3, 0xfc, 0x03, 0xf8, 0x10, 0x00, 0x11, 0xf8, 0x8a, 0x80, 0x2d, 0xe4, 0x44, 0x00, 0x4d, 0xee, 0xa8, 0x82, 0x9b, 0xcd, 0x50, 0x00, 0x17, 0xec, 0xa0, 0x8a, 0x2f, 0xcc, 0x00, 0x04, 0x67, 0xe8, 0x28, 0x1a, 0xff, 0xe4, 0x70, 0x4d, 0xcf, 0xfc, 0x82, 0xa7, 0xef, 0x90, 0x40, 0x13, 0xdf}; -// const uint8_t gun_mask[] = {0xff, 0xff, 0x8f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f}; -const uint8_t gun[] = {0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x01, 0xc4, 0x00, - 0x00, 0x02, 0x04, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0xea, 0x00, - 0x00, 0x04, 0xd1, 0x00, 0x00, 0x09, 0x88, 0x80, 0x00, 0x19, 0x00, 0x00, - 0x00, 0x0d, 0xc2, 0x80, 0x00, 0x29, 0x81, 0xc0, 0x00, 0x0b, 0xa2, 0x20, - 0x00, 0x31, 0x40, 0x40, 0x00, 0x23, 0x00, 0xc0, 0x00, 0x13, 0x00, 0x40, - 0x00, 0x72, 0x02, 0x00, 0x00, 0x49, 0x00, 0x40, 0x01, 0xe0, 0xa8, 0x20, - 0x07, 0xf1, 0x00, 0x30, 0x0b, 0xb9, 0xe0, 0xe8, 0x07, 0x5c, 0x03, 0xfc, - 0x07, 0xef, 0xff, 0xee, 0x07, 0x75, 0x7f, 0xd2, 0x1b, 0xbb, 0xff, 0xb2, - 0x11, 0x57, 0x7d, 0x64, 0x32, 0xaf, 0xff, 0xe8, 0x13, 0x5f, 0x75, 0xd0, - 0x33, 0xff, 0xfb, 0x98, 0x17, 0xd7, 0xe5, 0x00, 0x1b, 0x8f, 0xb2, 0x30, - 0x03, 0x7d, 0x58, 0x10, 0x6f, 0xbf, 0xec, 0x20}; -const uint8_t gun_mask[] = {0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x03, 0xfe, 0x00, - 0x00, 0x07, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, - 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, - 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xf0, - 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, - 0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfe, - 0x1f, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, - 0x3f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0}; - -const uint8_t - imp_inv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, - 0x02, 0x80, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x01, 0x0f, 0xb3, 0x00, 0x00, 0xd0, 0x4e, 0x00, 0x00, 0x79, 0x8c, - 0x00, 0x00, 0x1c, 0x19, 0x00, 0x01, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x40, 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8e, - 0x30, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xe0, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa1, 0x80, 0x01, 0x80, 0x13, 0x00, - 0x00, 0xf3, 0x8a, 0x00, 0x00, 0x09, 0x94, 0x00, 0x00, 0x88, 0x38, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x23, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, - 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, - 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, - 0x00, 0x1f, 0x00, 0x00, 0x02, 0x2a, 0x80, 0x00, 0x01, 0x05, 0x00, 0x00, 0x01, - 0xae, 0x20, 0x00, 0x01, 0x24, 0x40, 0x00, 0x02, 0xac, 0x80, 0x00, 0x02, 0x86, - 0x00, 0x00, 0x03, 0x20, 0x20, 0x00, 0x04, 0x30, 0x40, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x98, - 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0xd6, 0x80, 0x00, - 0x02, 0xbf, 0x80, 0x00, 0x06, 0x61, 0xa0, 0x00, 0x0c, 0xe8, 0x80, 0x00, 0x0c, - 0x10, 0x00, 0x00, 0x1a, 0x22, 0x00, 0x00, 0x12, 0x40, 0x00, 0x00, 0x06, 0x0c, - 0x00, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x3a, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, - 0x00, 0x60, 0x0a, 0x00, 0x00, 0x50, 0x04, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, - 0x18, 0x00, 0x00, 0x01, 0x41, 0x40, 0x02, 0x33, 0xb6, 0x80, 0x01, 0x9c, 0x04, - 0x00, 0x08, 0xfa, 0x02, 0x08, 0x05, 0x00, 0x01, 0x0c, 0x27, 0x83, 0xa2, 0x2a, - 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00}; //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0f, 0xb3, 0x00, 0x00, 0xd0, 0x4e, 0x00, 0x00, 0x79, 0x8c, 0x00, 0x00, 0x1c, 0x19, 0x00, 0x01, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8e, 0x30, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t imp_mask_inv[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, - 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x07, 0xf1, 0x80, - 0x00, 0xdf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, - 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xf1, 0xc0, 0x01, 0xc7, 0xf1, 0xc0, - 0x01, 0x87, 0xf1, 0xc0, 0x03, 0x0f, 0xf9, 0x80, 0x03, 0x0f, 0xfb, 0x80, 0x01, 0x8f, 0xff, 0x80, - 0x03, 0x9f, 0x79, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x0f, 0x78, 0x00, - 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x30, 0x00, - 0x00, 0x03, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, - 0x00, 0x07, 0xc0, 0x00, 0x01, 0x07, 0xe1, 0x00, 0x00, 0x8f, 0xfa, 0x00, 0x00, 0xff, 0xfe, 0x00, - 0x00, 0x3f, 0xfe, 0x00, 0x01, 0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, - 0x03, 0xcf, 0xfb, 0xc0, 0x03, 0x87, 0xf1, 0xc0, 0x03, 0xcf, 0xf3, 0xc0, 0x01, 0xcf, 0xf1, 0x80, - 0x00, 0xcf, 0xf1, 0x00, 0x00, 0x0f, 0xfb, 0x80, 0x00, 0x1e, 0x78, 0x00, 0x00, 0x0e, 0x78, 0x00, - 0x00, 0x1e, 0x78, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x07, 0x70, 0x00, - 0x00, 0x07, 0x70, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x03, 0x20, 0x00, - 0x00, 0x07, 0x30, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x00, - 0x00, 0x00, 0x1f, 0x00, 0x00, 0x03, 0x3f, 0x80, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x01, 0xff, 0x30, - 0x00, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x80, 0x00, 0x07, 0xff, 0xe0, - 0x00, 0x07, 0xff, 0xc0, 0x00, 0x05, 0xff, 0xe0, 0x00, 0x00, 0xfc, 0xe0, 0x00, 0x01, 0xfc, 0xe0, - 0x00, 0x01, 0xfc, 0x70, 0x00, 0x03, 0xfc, 0x38, 0x00, 0x03, 0xfe, 0x70, 0x00, 0x07, 0xfc, 0x00, - 0x00, 0x07, 0x9e, 0x00, 0x00, 0x0f, 0xbc, 0x00, 0x00, 0x0f, 0x3e, 0x00, 0x00, 0x07, 0x9c, 0x00, - 0x00, 0x03, 0x9c, 0x00, 0x00, 0x03, 0xb8, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0x98, 0x00, - 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1f, 0x00, - 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x3e, 0x80, 0x00, 0x01, 0xff, 0x80, 0x00, 0x03, 0xff, 0x80, - 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0e, 0xff, 0xc0, 0x00, 0x0c, 0xff, 0x80, 0x00, 0x1f, 0xfe, 0x00, - 0x00, 0x13, 0xfc, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x3f, 0x9f, 0x00, - 0x00, 0x3e, 0x0f, 0x00, 0x00, 0x7c, 0x0f, 0x00, 0x00, 0x78, 0x0f, 0x00, 0x00, 0x78, 0x07, 0x80, - 0x00, 0x78, 0x07, 0x40, 0x00, 0x38, 0x07, 0x80, 0x00, 0x30, 0x07, 0x00, 0x00, 0x30, 0x01, 0x00, - 0x01, 0xf0, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x00, - 0x00, 0x01, 0x3e, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x01, 0x3f, 0xff, 0xc0, - 0x01, 0xff, 0xff, 0xc0, 0x19, 0xff, 0xff, 0xe8, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, - 0x1f, 0xc2, 0x07, 0xe0, 0x1f, 0x00, 0x01, 0xe0, 0x0e, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, -}; //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x07, 0xf1, 0x80, 0x00, 0xdf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xf1, 0xc0, 0x01, 0xc7, 0xf1, 0xc0, 0x01, 0x87, 0xf1, 0xc0, 0x03, 0x0f, 0xf9, 0x80, 0x03, 0x0f, 0xfb, 0x80, 0x01, 0x8f, 0xff, 0x80, 0x03, 0x9f, 0x79, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t fireball[] = {0x00, 0x00, 0x01, 0x40, 0x0a, 0xb0, 0x0e, 0xd0, 0x00, 0x68, 0x53, - 0xb4, 0x0f, 0x48, 0x27, 0x78, 0x17, 0xa8, 0x27, 0xf0, 0x21, 0xd6, - 0x02, 0xf8, 0x20, 0x48, 0x06, 0x20, 0x01, 0x00, 0x00, 0x00}; -const uint8_t fireball_mask[] = {0x1f, 0x40, 0x0f, 0xf0, 0x3f, 0xf8, 0x1f, 0xfc, 0x7f, 0xfd, 0x7f, - 0xfc, 0x7f, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0x3f, 0xfe, 0x17, 0xf8, 0x07, 0xf4, 0x01, 0xe0}; -const uint8_t item[] = {0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x77, 0xee, 0x3f, - 0xfc, 0x5f, 0xfa, 0x2f, 0xf6, 0x53, 0xcc, 0x3e, 0x7e, 0x5e, 0x7c, - 0x38, 0x1e, 0x58, 0x1c, 0x3e, 0x7e, 0x5e, 0x7e, 0x2e, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x17, 0xfc, 0x22, 0x6c, 0x36, 0x44, 0x3f, 0xfc, 0x1f, 0xfc, 0x2b, - 0xfc, 0x05, 0x54, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x00}; -const uint8_t item_mask[] = {0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, - 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, - 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x1f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, - 0xfc, 0x07, 0xfc, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00}; - -//const uint8_t door[] = {0xff, 0xff, 0xff, 0xff,0xb2, 0xbd, 0xcd, 0x5b,0x9a, 0xf4, 0x6d, 0x71,0xff, 0xff, 0xff, 0xff,0x00, 0x00, 0x00, 0x00,0xbf, 0xff, 0xff, 0xfd,0x3f, 0x00, 0xfe, 0xfc,0x3e, 0x00, 0xc6, 0xfc,0xbc, 0xaa, 0xfe, 0xbd,0x39, 0x54, 0xc6, 0xbc,0x32, 0x8e, 0xfe, 0xac,0xb5, 0xfe, 0xc6, 0xad,0x3f, 0xe0, 0xfe, 0xac,0x31, 0xe0, 0xc6, 0xac,0xb3, 0xf4, 0xfe, 0xad,0x3f, 0xe8, 0xc6, 0xac,0x3c, 0xf4, 0xd6, 0xac,0xb8, 0xff, 0xfe, 0xad,0x34, 0xc7, 0xfe, 0xfc,0x38, 0xd6, 0x0e, 0x0c,0xb0, 0xd6, 0x4e, 0x0d,0x3f, 0xd6, 0xaf, 0x5c,0x30, 0x47, 0xff, 0xac,0xb7, 0x57, 0xff, 0xfd,0x3f, 0xc6, 0x0e, 0x0c,0x35, 0x56, 0x40, 0x4c,0xb5, 0x46, 0xaa, 0xad,0x35, 0x56, 0x55, 0x4c,0xff, 0xff, 0xff, 0xff,0xb0, 0x1f, 0xf8, 0x0d,0xd9, 0x30, 0x0c, 0x9b,0xff, 0xe0, 0x07, 0xff}; -const uint8_t door[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0xe1, 0x8c, 0x00, 0x04, - 0x00, 0x7c, 0x03, 0x18, 0x60, 0x08, 0x00, 0x3e, 0x0f, 0xf7, 0xdf, 0x00, 0x1f, 0x00, 0xfe, 0x0f, - 0xbe, 0xf8, 0x3e, 0x00, 0x3f, 0x1f, 0xff, 0xdf, 0x00, 0x1f, 0x81, 0xff, 0x0f, 0xff, 0xf8, 0x7e, - 0x00, 0x3f, 0x8f, 0xff, 0xdf, 0x00, 0xff, 0xf9, 0xff, 0x1f, 0xff, 0xf8, 0xff, 0x80, 0x3f, 0xc7, - 0xff, 0xcc, 0x07, 0xff, 0xfc, 0xff, 0x1f, 0xff, 0xe3, 0xff, 0x80, 0x3f, 0xc7, 0xff, 0xc0, 0x07, - 0xff, 0xfc, 0x7f, 0x0f, 0xfe, 0x03, 0xff, 0xc0, 0x3f, 0xc3, 0xf7, 0xc0, 0x07, 0xdf, 0xf8, 0x3e, - 0x0f, 0xbe, 0x01, 0xff, 0x80, 0x1f, 0x80, 0xe3, 0x80, 0x07, 0x8f, 0xf8, 0x1e, 0x07, 0x1c, 0x01, - 0xff, 0x80, 0x3f, 0xc1, 0xff, 0xc0, 0x0f, 0xff, 0xfc, 0x3f, 0x0f, 0xbe, 0x03, 0xff, 0xc0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x80, 0x00, - 0x7f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x1f, 0xf0, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, - 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, - 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xf0, 0x00, 0x0f, - 0xf0, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0x81, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, - 0x07, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x0f, 0xff, 0xff, - 0xff, 0xe1, 0xff, 0xe1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0xff, - 0xc1, 0xf3, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0xff, 0x81, 0xff, 0xc0, - 0x0f, 0xf0, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0x01, 0xff, 0xc0, 0x0f, 0xf0, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x01, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xe1, - 0xff, 0xe1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, - 0xf0, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x8f, 0xe0, 0xff, 0x81, 0xff, 0xff, 0x0f, 0xf0, - 0xff, 0x1f, 0xff, 0xff, 0xfe, 0x07, 0xe0, 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, - 0xff, 0xfc, 0x07, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x8f, 0xfc, 0x03, - 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x07, 0xfc, 0x07, 0xe0, 0xff, 0xc1, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, - 0xf0, 0xff, 0x0f, 0x9c, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, - 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xfc, 0x00, 0x7f, - 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, - 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, - 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, - 0x1f, 0xfc, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfc, 0x00, - 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, - 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0xff, 0x81, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x1f, - 0x80, 0x3f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x3f, 0xc0, 0x1f, 0xff, - 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x7f, 0xc0, 0x0f, 0xff, 0xe1, 0xff, 0xe1, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0xff, 0xc0, 0x07, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, - 0xf0, 0xff, 0x01, 0xff, 0xc0, 0x03, 0x8f, 0xc0, 0xc1, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x03, - 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xff, 0xc0, 0xff, - 0x80, 0x00, 0x00, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc1, 0xff, 0x80, 0x00, 0x00, - 0x01, 0xf3, 0x8e, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0x9c, - 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0xff, 0xfc, 0x01, 0xff, 0xfe, 0x0f, 0xf0, 0xff, - 0x0f, 0xff, 0xc3, 0xff, 0xc1, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xc3, - 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, - 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, - 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, - 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xe3, 0xff, 0xc3, 0xff, 0xff, 0x00, - 0x3f, 0xfe, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xf3, 0xff, 0xc1, 0xef, 0xfe, 0x00, 0x3f, 0xfe, 0x0f, - 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x82, 0x00, 0x00, 0x1f, 0xff, 0x0f, 0xf0, 0xff, 0x1f, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, - 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x0f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, - 0x00, 0x03, 0x8e, 0x0f, 0xf0, 0xff, 0x1f, 0xc1, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x88, - 0x0f, 0xf0, 0xff, 0x0f, 0x80, 0xff, 0xff, 0xc1, 0xff, 0xfc, 0x00, 0xff, 0xfe, 0x0f, 0xf0, 0xff, - 0x06, 0x00, 0x73, 0xff, 0xc3, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0x03, - 0xff, 0xc3, 0xff, 0xff, 0x83, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0x0c, 0x73, 0xff, 0xc3, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, - 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, - 0xf0, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xf0, 0xfe, 0x1f, - 0xfe, 0xfb, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfc, 0x0f, 0x9e, 0x73, 0xff, - 0x81, 0xf9, 0xf7, 0xe7, 0x9c, 0xff, 0x03, 0xf0, 0xfc, 0x07, 0xfe, 0xfb, 0xc0, 0x00, 0xf0, 0x00, - 0x6f, 0xbe, 0xfe, 0x03, 0xf0, 0x3c, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, - 0x03, 0xc0, 0x1c, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x03, 0x80, 0x1e, - 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x07, 0x80, 0x3f, 0x0f, 0xff, 0xff, - 0xe0, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0x0f, 0xc0, 0x1f, 0x8f, 0xff, 0xff, 0xe7, 0xff, 0xff, - 0xfe, 0x7f, 0xff, 0xff, 0x1f, 0x80, 0x1f, 0xc7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x3f, 0x80, 0x07, 0xc3, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xfc, 0x3e, 0x00, - 0x07, 0xc1, 0xfe, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xf7, 0xf8, 0x3e, 0x00, 0x01, 0x00, 0xfc, - 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xe7, 0xe3, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, - 0x00, 0x00, 0x00, 0x00}; \ No newline at end of file diff --git a/applications/external/doom/assets.h b/applications/external/doom/assets.h deleted file mode 100644 index 546d7607d..000000000 --- a/applications/external/doom/assets.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once -#include - -#ifndef _sprites_h -#define _sprites_h - -#define bmp_font_width 24 // in bytes -#define bmp_font_height 6 -#define bmp_font_width_pxs 192 -#define bmp_font_height_pxs 48 -#define CHAR_MAP " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#" -#define CHAR_WIDTH 4 -#define CHAR_HEIGHT 6 - -#define BMP_GUN_WIDTH 32 -#define BMP_GUN_HEIGHT 32 - -#define BMP_FIRE_WIDTH 24 -#define BMP_FIRE_HEIGHT 20 - -#define BMP_IMP_WIDTH 32 -#define BMP_IMP_HEIGHT 32 -#define BMP_IMP_COUNT 5 - -#define BMP_FIREBALL_WIDTH 16 -#define BMP_FIREBALL_HEIGHT 16 - -#define BMP_DOOR_WIDTH 100 -#define BMP_DOOR_HEIGHT 100 - -#define BMP_ITEMS_WIDTH 16 -#define BMP_ITEMS_HEIGHT 16 -#define BMP_ITEMS_COUNT 2 - -#define BMP_LOGO_WIDTH 128 -#define BMP_LOGO_HEIGHT 64 - -#define GRADIENT_WIDTH 2 -#define GRADIENT_HEIGHT 8 -#define GRADIENT_COUNT 8 -#define GRADIENT_WHITE 7 -#define GRADIENT_BLACK 0 - -// Fonts -extern const uint8_t zero[]; -extern const uint8_t one[]; -extern const uint8_t two[]; -extern const uint8_t three[]; -extern const uint8_t four[]; -extern const uint8_t five[]; -extern const uint8_t six[]; -extern const uint8_t seven[]; -extern const uint8_t eight[]; -extern const uint8_t nine[]; -extern const uint8_t A[]; -extern const uint8_t B[]; -extern const uint8_t C[]; -extern const uint8_t D[]; -extern const uint8_t E[]; -extern const uint8_t F[]; -extern const uint8_t G[]; -extern const uint8_t H[]; -extern const uint8_t I[]; -extern const uint8_t J[]; -extern const uint8_t K[]; -extern const uint8_t L[]; -extern const uint8_t M[]; -extern const uint8_t N[]; -extern const uint8_t O[]; -extern const uint8_t P[]; -extern const uint8_t Q[]; -extern const uint8_t R[]; -extern const uint8_t S[]; -extern const uint8_t T[]; -extern const uint8_t U[]; -extern const uint8_t V[]; -extern const uint8_t W[]; -extern const uint8_t X[]; -extern const uint8_t Y[]; -extern const uint8_t Z[]; -extern const uint8_t dot[]; -extern const uint8_t comma[]; -extern const uint8_t dash[]; -extern const uint8_t underscore[]; -extern const uint8_t bracket_open[]; -extern const uint8_t bracket_close[]; -extern const uint8_t cross_left[]; -extern const uint8_t cross_right[]; -extern const uint8_t pacman_left[]; -extern const uint8_t pacman_right[]; -extern const uint8_t box[]; -extern const uint8_t* char_arr[48]; -extern const uint8_t gradient[]; -//extern const uint8_t gun[] -//extern const uint8_t gun_mask[] -extern const uint8_t gun[]; -extern const uint8_t gun_mask[]; - -extern const uint8_t imp_inv[]; -extern const uint8_t imp_mask_inv[]; -extern const uint8_t fireball[]; -extern const uint8_t fireball_mask[]; -extern const uint8_t item[]; -extern const uint8_t item_mask[]; - -extern const uint8_t door[]; - -#endif diff --git a/applications/external/doom/assets/door2.png b/applications/external/doom/assets/door2.png deleted file mode 100644 index b4b4f0399..000000000 Binary files a/applications/external/doom/assets/door2.png and /dev/null differ diff --git a/applications/external/doom/assets/door_inv.png b/applications/external/doom/assets/door_inv.png deleted file mode 100644 index 3185f524c..000000000 Binary files a/applications/external/doom/assets/door_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/fire_inv.png b/applications/external/doom/assets/fire_inv.png deleted file mode 100644 index 46af8691b..000000000 Binary files a/applications/external/doom/assets/fire_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/fireball_inv.png b/applications/external/doom/assets/fireball_inv.png deleted file mode 100644 index b046288f8..000000000 Binary files a/applications/external/doom/assets/fireball_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/fireball_mask_inv.png b/applications/external/doom/assets/fireball_mask_inv.png deleted file mode 100644 index 548c654b7..000000000 Binary files a/applications/external/doom/assets/fireball_mask_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/gradient_inv.png b/applications/external/doom/assets/gradient_inv.png deleted file mode 100644 index 78eec8c20..000000000 Binary files a/applications/external/doom/assets/gradient_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/gun_inv.png b/applications/external/doom/assets/gun_inv.png deleted file mode 100644 index e2ec05295..000000000 Binary files a/applications/external/doom/assets/gun_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/gun_mask_inv.png b/applications/external/doom/assets/gun_mask_inv.png deleted file mode 100644 index 2d761a70a..000000000 Binary files a/applications/external/doom/assets/gun_mask_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/imp_inv.png b/applications/external/doom/assets/imp_inv.png deleted file mode 100644 index 4b480f1c5..000000000 Binary files a/applications/external/doom/assets/imp_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/imp_mask_inv.png b/applications/external/doom/assets/imp_mask_inv.png deleted file mode 100644 index 70e991270..000000000 Binary files a/applications/external/doom/assets/imp_mask_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/item_inv.png b/applications/external/doom/assets/item_inv.png deleted file mode 100644 index 1d32dbcd8..000000000 Binary files a/applications/external/doom/assets/item_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/item_mask_inv.png b/applications/external/doom/assets/item_mask_inv.png deleted file mode 100644 index a0bde9c76..000000000 Binary files a/applications/external/doom/assets/item_mask_inv.png and /dev/null differ diff --git a/applications/external/doom/assets/logo_inv.png b/applications/external/doom/assets/logo_inv.png deleted file mode 100644 index c75bd3028..000000000 Binary files a/applications/external/doom/assets/logo_inv.png and /dev/null differ diff --git a/applications/external/doom/constants.h b/applications/external/doom/constants.h deleted file mode 100644 index 4e0f10118..000000000 --- a/applications/external/doom/constants.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _constants_h -#define _constants_h -#define PB_CONSTEXPR constexpr - -#define PI 3.14159265358979323846 - -// Key pinout -#define USE_INPUT_PULLUP -#define K_LEFT 6 -#define K_RIGHT 7 -#define K_UP 8 -#define K_DOWN 3 -#define K_FIRE 10 - -// SNES Controller -// uncomment following line to enable snes controller support -// #define SNES_CONTROLLER -const uint8_t DATA_CLOCK = 11; -const uint8_t DATA_LATCH = 12; -const uint8_t DATA_SERIAL = 13; - -// Sound -const uint8_t SOUND_PIN = 9; // do not change, belongs to used timer - -// GFX settings -#define OPTIMIZE_SSD1306 // Optimizations for SSD1366 displays - -#define FRAME_TIME 66.666666 // Desired time per frame in ms (66.666666 is ~15 fps) -#define RES_DIVIDER 2 - -/* Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage - Lower will require more process and memory, but looks nicer - */ -#define Z_RES_DIVIDER 2 // Zbuffer resolution divider. We sacrifice resolution to save memory -#define DISTANCE_MULTIPLIER 20 - -/* Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care - of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH - */ - -#define MAX_RENDER_DEPTH 12 -#define MAX_SPRITE_DEPTH 8 - -#define ZBUFFER_SIZE SCREEN_WIDTH / Z_RES_DIVIDER - -// Level -#define LEVEL_WIDTH_BASE 6 -#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE) -#define LEVEL_HEIGHT 57 -#define LEVEL_SIZE LEVEL_WIDTH / 2 * LEVEL_HEIGHT - -// scenes -#define INTRO 0 -#define GAME_PLAY 1 - -// Game -#define GUN_TARGET_POS 18 -#define GUN_SHOT_POS GUN_TARGET_POS + 4 - -#define ROT_SPEED .12 -#define MOV_SPEED .2 -#define MOV_SPEED_INV 5 // 1 / MOV_SPEED - -#define JOGGING_SPEED .005 -#define ENEMY_SPEED .02 -#define FIREBALL_SPEED .2 -#define FIREBALL_ANGLES 45 // Num of angles per PI - -#define MAX_ENTITIES 10 // Max num of active entities -#define MAX_STATIC_ENTITIES 28 // Max num of entities in sleep mode - -#define MAX_ENTITY_DISTANCE 200 // * DISTANCE_MULTIPLIER -#define MAX_ENEMY_VIEW 80 // * DISTANCE_MULTIPLIER -#define ITEM_COLLIDER_DIST 6 // * DISTANCE_MULTIPLIER -#define ENEMY_COLLIDER_DIST 4 // * DISTANCE_MULTIPLIER -#define FIREBALL_COLLIDER_DIST 2 // * DISTANCE_MULTIPLIER -#define ENEMY_MELEE_DIST 6 // * DISTANCE_MULTIPLIER -#define WALL_COLLIDER_DIST .2 - -#define ENEMY_MELEE_DAMAGE 8 -#define ENEMY_FIREBALL_DAMAGE 20 -#define GUN_MAX_DAMAGE 20 - -// display -const uint8_t SCREEN_WIDTH = 128; -const uint8_t SCREEN_HEIGHT = 64; -const uint8_t HALF_WIDTH = SCREEN_WIDTH / 2; -const uint8_t RENDER_HEIGHT = 56; // raycaster working height (the rest is for the hud) -const uint8_t HALF_HEIGHT = SCREEN_HEIGHT / 2; - -#endif diff --git a/applications/external/doom/display.h b/applications/external/doom/display.h deleted file mode 100644 index a949b14fa..000000000 --- a/applications/external/doom/display.h +++ /dev/null @@ -1,281 +0,0 @@ -#include -#include -#include "constants.h" -#include "doom_icons.h" -#include -#include "assets.h" - -#define CHECK_BIT(var, pos) ((var) & (1 << (pos))) - -static const uint8_t bit_mask[8] = {128, 64, 32, 16, 8, 4, 2, 1}; - -#define pgm_read_byte(addr) (*(const unsigned char*)(addr)) -#define read_bit(b, n) b& pgm_read_byte(bit_mask + n) ? 1 : 0 -//#define read_bit(byte, index) (((unsigned)(byte) >> (index)) & 1) - -void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas); -void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas); -void drawSprite( - int8_t x, - int8_t y, - const uint8_t* bitmap, - const uint8_t* bitmap_mask, - int16_t w, - int16_t h, - uint8_t sprite, - double distance, - Canvas* const canvas); -void drawBitmap( - int16_t x, - int16_t y, - const Icon* i, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas); -void drawTextSpace(int8_t x, int8_t y, char* txt, uint8_t space, Canvas* const canvas); -void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas); -void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas); -void drawGun( - int16_t x, - int16_t y, - const uint8_t* bitmap, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas); -void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas); -void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas); -void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas); -bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i); -double getActualFps(); -void fps(); -uint8_t reverse_bits(uint8_t num); - -// FPS control -double delta = 1; -uint32_t lastFrameTime = 0; -uint8_t zbuffer[128]; /// 128 = screen width & REMOVE WHEN DISPLAY.H IMPLEMENTED - -void drawGun( - int16_t x, - int16_t y, - const uint8_t* bitmap, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas) { - int16_t byteWidth = (w + 7) / 8; - uint8_t byte = 0; - for(int16_t j = 0; j < h; j++, y++) { - for(int16_t i = 0; i < w; i++) { - if(i & 7) - byte <<= 1; - else - byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); - if(byte & 0x80) drawPixel(x + i, y, color, false, canvas); - } - } -} - -void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas) { - UNUSED(intensity); - uint8_t dots = end_y - start_y; - for(int i = 0; i < dots; i++) { - canvas_draw_dot(canvas, x, start_y + i); - } -} - -void drawBitmap( - int16_t x, - int16_t y, - const Icon* i, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas) { - UNUSED(w); - UNUSED(h); - if(!color) { - canvas_invert_color(canvas); - } - canvas_draw_icon(canvas, x, y, i); - if(!color) { - canvas_invert_color(canvas); - } -} - -void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas) { - char buf[4]; - snprintf(buf, 4, "%d", num); - drawTextSpace(x, y, buf, 1, canvas); -} - -void drawTextSpace(int8_t x, int8_t y, char* txt, uint8_t space, Canvas* const canvas) { - uint8_t pos = x; - uint8_t i = 0; - char ch; - while((ch = txt[i]) != '\0') { - drawChar(pos, y, ch, canvas); - i++; - pos += CHAR_WIDTH + space; - - // shortcut on end of screen - if(pos > SCREEN_WIDTH) return; - } -} - -// Custom drawBitmap method with scale support, mask, zindex and pattern filling -void drawSprite( - int8_t x, - int8_t y, - const uint8_t* bitmap, - const uint8_t* bitmap_mask, - int16_t w, - int16_t h, - uint8_t sprite, - double distance, - Canvas* const canvas) { - uint8_t tw = (double)w / distance; - uint8_t th = (double)h / distance; - uint8_t byte_width = w / 8; - uint8_t pixel_size = fmax(1, (double)1.0 / (double)distance); - uint16_t sprite_offset = byte_width * h * sprite; - - bool pixel; - bool maskPixel; - - // Don't draw the whole sprite if the anchor is hidden by z buffer - // Not checked per pixel for performance reasons - if(zbuffer[(int)(fmin(fmax(x, 0), ZBUFFER_SIZE - 1) / Z_RES_DIVIDER)] < - distance * DISTANCE_MULTIPLIER) { - return; - } - - for(uint8_t ty = 0; ty < th; ty += pixel_size) { - // Don't draw out of screen - if(y + ty < 0 || y + ty >= RENDER_HEIGHT) { - continue; - } - - uint8_t sy = ty * distance; // The y from the sprite - - for(uint8_t tx = 0; tx < tw; tx += pixel_size) { - uint8_t sx = tx * distance; // The x from the sprite - uint16_t byte_offset = sprite_offset + sy * byte_width + sx / 8; - - // Don't draw out of screen - if(x + tx < 0 || x + tx >= SCREEN_WIDTH) { - continue; - } - - maskPixel = read_bit(pgm_read_byte(bitmap_mask + byte_offset), sx % 8); - - if(maskPixel) { - pixel = read_bit(pgm_read_byte(bitmap + byte_offset), sx % 8); - for(uint8_t ox = 0; ox < pixel_size; ox++) { - for(uint8_t oy = 0; oy < pixel_size; oy++) { - if(bitmap == imp_inv) - drawPixel(x + tx + ox, y + ty + oy, 1, true, canvas); - else - drawPixel(x + tx + ox, y + ty + oy, pixel, true, canvas); - } - } - } - } - } -} - -void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas) { - if(x < 0 || x >= SCREEN_WIDTH || y < 0 || - y >= (raycasterViewport ? RENDER_HEIGHT : SCREEN_HEIGHT)) { - return; - } - if(color) - canvas_draw_dot(canvas, x, y); - else { - canvas_invert_color(canvas); - canvas_draw_dot(canvas, x, y); - canvas_invert_color(canvas); - } -} - -void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas) { - uint8_t lsb; - uint8_t c = 0; - while(CHAR_MAP[c] != ch && CHAR_MAP[c] != '\0') c++; - for(uint8_t i = 0; i < 6; i++) { - //lsb = (char_arr[c][i] >> 4); - lsb = reverse_bits(char_arr[c][i]); - for(uint8_t n = 0; n < 4; n++) { - if(CHECK_BIT(lsb, n)) { - drawPixel(x + n, y + i, true, false, canvas); - } - } - } -} - -void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas) { - canvas_invert_color(canvas); - - for(int i = 0; i < w; i++) { - for(int j = 0; j < h; j++) { - canvas_draw_dot(canvas, x + i, y + j); - } - } - - canvas_invert_color(canvas); -} - -void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas) { - for(int i = 0; i < w; i++) { - for(int j = 0; j < h; j++) { - canvas_draw_dot(canvas, x + i, y + j); - } - } -} - -bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i) { - if(i == 0) return 0; - if(i >= GRADIENT_COUNT - 1) return 1; - - uint8_t index = - fmax(0, fmin(GRADIENT_COUNT - 1, i)) * GRADIENT_WIDTH * GRADIENT_HEIGHT // gradient index - + y * GRADIENT_WIDTH % (GRADIENT_WIDTH * GRADIENT_HEIGHT) // y byte offset - + x / GRADIENT_HEIGHT % GRADIENT_WIDTH; // x byte offset - //uint8_t *gradient_data = NULL; - //furi_hal_compress_icon_decode(icon_get_data(&I_gradient_inv), &gradient_data); - // return the bit based on x - return read_bit(pgm_read_byte(gradient + index), x % 8); -} - -void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas) { - for(uint8_t x = 0; x < SCREEN_WIDTH; x++) { - for(uint8_t y = 0; y < SCREEN_HEIGHT; y++) { - if(getGradientPixel(x, y, intensity)) drawPixel(x, y, color, false, canvas); - } - } -} - -// Adds a delay to limit play to specified fps -// Calculates also delta to keep movement consistent in lower framerates -void fps() { - while(furi_get_tick() - lastFrameTime < FRAME_TIME) - ; - delta = (double)(furi_get_tick() - lastFrameTime) / (double)FRAME_TIME; - lastFrameTime = furi_get_tick(); -} - -double getActualFps() { - return 1000 / ((double)FRAME_TIME * (double)delta); -} - -uint8_t reverse_bits(uint8_t num) { - unsigned int NO_OF_BITS = sizeof(num) * 8; - uint8_t reverse_num = 0; - uint8_t i; - for(i = 0; i < NO_OF_BITS; i++) { - if((num & (1 << i))) reverse_num |= 1 << ((NO_OF_BITS - 1) - i); - } - return reverse_num; -} \ No newline at end of file diff --git a/applications/external/doom/doom.c b/applications/external/doom/doom.c deleted file mode 100644 index c2d9a6bf0..000000000 --- a/applications/external/doom/doom.c +++ /dev/null @@ -1,1104 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "sound.h" -#include "display.h" -#include "assets.h" -#include "constants.h" -#include "entities.h" -#include "types.h" -#include "level.h" -#include -#include -#include - -#define SOUND - -// Useful macros -#define swap(a, b) \ - do { \ - typeof(a) temp = a; \ - a = b; \ - b = temp; \ - } while(0) -#define sign(a, b) (double)(a > b ? 1 : (b > a ? -1 : 0)) -#define pgm_read_byte(addr) (*(const unsigned char*)(addr)) - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - Player player; - Entity entity[MAX_ENTITIES]; - StaticEntity static_entity[MAX_STATIC_ENTITIES]; - uint8_t num_entities; - uint8_t num_static_entities; - - uint8_t scene; - uint8_t gun_pos; - double jogging; - double view_height; - bool init; - - bool up; - bool down; - bool left; - bool right; - bool fired; - bool gun_fired; - - double rot_speed; - double old_dir_x; - double old_plane_x; - NotificationApp* notify; -#ifdef SOUND - MusicPlayer* music_instance; - bool intro_sound; -#endif -} PluginState; - -static const NotificationSequence sequence_short_sound = { - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; -static const NotificationSequence sequence_long_sound = { - &message_note_c3, - &message_delay_100, - &message_sound_off, - NULL, -}; - -Coords translateIntoView(Coords* pos, PluginState* const plugin_state); -void updateHud(Canvas* const canvas, PluginState* const plugin_state); -// general - -bool invert_screen = false; -uint8_t flash_screen = 0; - -// game -// player and entities - -uint8_t getBlockAt(const uint8_t level[], uint8_t x, uint8_t y) { - if(x >= LEVEL_WIDTH || y >= LEVEL_HEIGHT) { - return E_FLOOR; - } - - // y is read in inverse order - return pgm_read_byte(level + (((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2)) >> - (!(x % 2) * 4) // displace part of wanted bits - & 0b1111; // mask wanted bits -} - -// Finds the player in the map -void initializeLevel(const uint8_t level[], PluginState* const plugin_state) { - for(uint8_t y = LEVEL_HEIGHT - 1; y > 0; y--) { - for(uint8_t x = 0; x < LEVEL_WIDTH; x++) { - uint8_t block = getBlockAt(level, x, y); - - if(block == E_PLAYER) { - plugin_state->player = create_player(x, y); - return; - } - - // todo create other static entities - } - } -} - -bool isSpawned(UID uid, PluginState* const plugin_state) { - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - if(plugin_state->entity[i].uid == uid) return true; - } - - return false; -} - -bool isStatic(UID uid, PluginState* const plugin_state) { - for(uint8_t i = 0; i < plugin_state->num_static_entities; i++) { - if(plugin_state->static_entity[i].uid == uid) return true; - } - - return false; -} - -void spawnEntity(uint8_t type, uint8_t x, uint8_t y, PluginState* const plugin_state) { - // Limit the number of spawned entities - if(plugin_state->num_entities >= MAX_ENTITIES) { - return; - } - - // todo: read static entity status - - switch(type) { - case E_ENEMY: - plugin_state->entity[plugin_state->num_entities] = create_enemy(x, y); - plugin_state->num_entities++; - break; - - case E_KEY: - plugin_state->entity[plugin_state->num_entities] = create_key(x, y); - plugin_state->num_entities++; - break; - - case E_MEDIKIT: - plugin_state->entity[plugin_state->num_entities] = create_medikit(x, y); - plugin_state->num_entities++; - break; - } -} - -void spawnFireball(double x, double y, PluginState* const plugin_state) { - // Limit the number of spawned entities - if(plugin_state->num_entities >= MAX_ENTITIES) { - return; - } - - UID uid = create_uid(E_FIREBALL, x, y); - // Remove if already exists, don't throw anything. Not the best, but shouldn't happen too often - if(isSpawned(uid, plugin_state)) return; - - // Calculate direction. 32 angles - int16_t dir = - FIREBALL_ANGLES + atan2(y - plugin_state->player.pos.y, x - plugin_state->player.pos.x) / - (double)PI * FIREBALL_ANGLES; - if(dir < 0) dir += FIREBALL_ANGLES * 2; - plugin_state->entity[plugin_state->num_entities] = create_fireball(x, y, dir); - plugin_state->num_entities++; -} - -void removeEntity(UID uid, PluginState* const plugin_state) { - uint8_t i = 0; - bool found = false; - - while(i < plugin_state->num_entities) { - if(!found && plugin_state->entity[i].uid == uid) { - // todo: doze it - found = true; - plugin_state->num_entities--; - } - - // displace entities - if(found) { - plugin_state->entity[i] = plugin_state->entity[i + 1]; - } - - i++; - } -} - -void removeStaticEntity(UID uid, PluginState* const plugin_state) { - uint8_t i = 0; - bool found = false; - - while(i < plugin_state->num_static_entities) { - if(!found && plugin_state->static_entity[i].uid == uid) { - found = true; - plugin_state->num_static_entities--; - } - - // displace entities - if(found) { - plugin_state->static_entity[i] = plugin_state->static_entity[i + 1]; - } - - i++; - } -} - -UID detectCollision( - const uint8_t level[], - Coords* pos, - double relative_x, - double relative_y, - bool only_walls, - PluginState* const plugin_state) { - // Wall collision - uint8_t round_x = (int)(pos->x + relative_x); - uint8_t round_y = (int)(pos->y + relative_y); - uint8_t block = getBlockAt(level, round_x, round_y); - - if(block == E_WALL) { - // playSound(hit_wall_snd, HIT_WALL_SND_LEN); - return create_uid(block, round_x, round_y); - } - - if(only_walls) { - return UID_null; - } - - // Entity collision - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - // Don't collide with itself - if(&(plugin_state->entity[i].pos) == pos) { - continue; - } - - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - // Only ALIVE enemy collision - if(type != E_ENEMY || plugin_state->entity[i].state == S_DEAD || - plugin_state->entity[i].state == S_HIDDEN) { - continue; - } - - Coords new_coords = { - plugin_state->entity[i].pos.x - relative_x, - plugin_state->entity[i].pos.y - relative_y}; - uint8_t distance = coords_distance(pos, &new_coords); - - // Check distance and if it's getting closer - if(distance < ENEMY_COLLIDER_DIST && distance < plugin_state->entity[i].distance) { - return plugin_state->entity[i].uid; - } - } - - return UID_null; -} - -// Shoot -void fire(PluginState* const plugin_state) { - //playSound(shoot_snd, SHOOT_SND_LEN); - - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - // Shoot only ALIVE enemies - if(uid_get_type(plugin_state->entity[i].uid) != E_ENEMY || - plugin_state->entity[i].state == S_DEAD || plugin_state->entity[i].state == S_HIDDEN) { - continue; - } - - Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state); - if(fabs(transform.x) < 20 && transform.y > 0) { - uint8_t damage = (double)fmin( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / (fabs(transform.x) * plugin_state->entity[i].distance) / 5); - if(damage > 0) { - plugin_state->entity[i].health = fmax(0, plugin_state->entity[i].health - damage); - plugin_state->entity[i].state = S_HIT; - plugin_state->entity[i].timer = 4; - } - } - } -} - -UID updatePosition( - const uint8_t level[], - Coords* pos, - double relative_x, - double relative_y, - bool only_walls, - PluginState* const plugin_state) { - UID collide_x = detectCollision(level, pos, relative_x, 0, only_walls, plugin_state); - UID collide_y = detectCollision(level, pos, 0, relative_y, only_walls, plugin_state); - - if(!collide_x) pos->x += relative_x; - if(!collide_y) pos->y += relative_y; - - return collide_x || collide_y || UID_null; -} - -void updateEntities(const uint8_t level[], Canvas* const canvas, PluginState* const plugin_state) { - uint8_t i = 0; - while(i < plugin_state->num_entities) { - // update distance - plugin_state->entity[i].distance = - coords_distance(&(plugin_state->player.pos), &(plugin_state->entity[i].pos)); - - // Run the timer. Works with actual frames. - // Todo: use delta here. But needs double type and more memory - if(plugin_state->entity[i].timer > 0) plugin_state->entity[i].timer--; - - // too far away. put it in doze mode - if(plugin_state->entity[i].distance > MAX_ENTITY_DISTANCE) { - removeEntity(plugin_state->entity[i].uid, plugin_state); - // don't increase 'i', since current one has been removed - continue; - } - - // bypass render if hidden - if(plugin_state->entity[i].state == S_HIDDEN) { - i++; - continue; - } - - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - switch(type) { - case E_ENEMY: { - // Enemy "IA" - if(plugin_state->entity[i].health == 0) { - if(plugin_state->entity[i].state != S_DEAD) { - plugin_state->entity[i].state = S_DEAD; - plugin_state->entity[i].timer = 6; - } - } else if(plugin_state->entity[i].state == S_HIT) { - if(plugin_state->entity[i].timer == 0) { - // Back to alert state - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 40; // delay next fireball thrown - } - } else if(plugin_state->entity[i].state == S_FIRING) { - if(plugin_state->entity[i].timer == 0) { - // Back to alert state - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 40; // delay next fireball throwm - } - } else { - // ALERT STATE - if(plugin_state->entity[i].distance > ENEMY_MELEE_DIST && - plugin_state->entity[i].distance < MAX_ENEMY_VIEW) { - if(plugin_state->entity[i].state != S_ALERT) { - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 20; // used to throw fireballs - } else { - if(plugin_state->entity[i].timer == 0) { - // Throw a fireball - spawnFireball( - plugin_state->entity[i].pos.x, - plugin_state->entity[i].pos.y, - plugin_state); - plugin_state->entity[i].state = S_FIRING; - plugin_state->entity[i].timer = 6; - } else { - // move towards to the player. - updatePosition( - level, - &(plugin_state->entity[i].pos), - sign(plugin_state->player.pos.x, plugin_state->entity[i].pos.x) * - (double)ENEMY_SPEED * 1, // NOT SURE (delta) - sign(plugin_state->player.pos.y, plugin_state->entity[i].pos.y) * - (double)ENEMY_SPEED * 1, // NOT SURE (delta) - true, - plugin_state); - } - } - } else if(plugin_state->entity[i].distance <= ENEMY_MELEE_DIST) { - if(plugin_state->entity[i].state != S_MELEE) { - // Preparing the melee attack - plugin_state->entity[i].state = S_MELEE; - plugin_state->entity[i].timer = 10; - } else if(plugin_state->entity[i].timer == 0) { - // Melee attack - plugin_state->player.health = - fmax(0, plugin_state->player.health - ENEMY_MELEE_DAMAGE); - plugin_state->entity[i].timer = 14; - flash_screen = 1; - updateHud(canvas, plugin_state); - } - } else { - // stand - plugin_state->entity[i].state = S_STAND; - } - } - break; - } - - case E_FIREBALL: { - if(plugin_state->entity[i].distance < FIREBALL_COLLIDER_DIST) { - // Hit the player and disappear - plugin_state->player.health = - fmax(0, plugin_state->player.health - ENEMY_FIREBALL_DAMAGE); - flash_screen = 1; - updateHud(canvas, plugin_state); - removeEntity(plugin_state->entity[i].uid, plugin_state); - continue; // continue in the loop - } else { - // Move. Only collide with walls. - // Note: using health to store the angle of the movement - UID collided = updatePosition( - level, - &(plugin_state->entity[i].pos), - cos((double)plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * - (double)FIREBALL_SPEED, - sin((double)plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * - (double)FIREBALL_SPEED, - true, - plugin_state); - - if(collided) { - removeEntity(plugin_state->entity[i].uid, plugin_state); - continue; // continue in the entity check loop - } - } - break; - } - - case E_MEDIKIT: { - if(plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) { - // pickup - notification_message(plugin_state->notify, &sequence_long_sound); - //playSound(medkit_snd, MEDKIT_SND_LEN); - plugin_state->entity[i].state = S_HIDDEN; - plugin_state->player.health = fmin(100, plugin_state->player.health + 50); - updateHud(canvas, plugin_state); - flash_screen = 1; - } - break; - } - - case E_KEY: { - if(plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) { - // pickup - notification_message(plugin_state->notify, &sequence_long_sound); - //playSound(get_key_snd, GET_KEY_SND_LEN); - plugin_state->entity[i].state = S_HIDDEN; - plugin_state->player.keys++; - updateHud(canvas, plugin_state); - flash_screen = 1; - } - break; - } - } - - i++; - } -} - -// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html -void renderMap( - const uint8_t level[], - double view_height, - Canvas* const canvas, - PluginState* const plugin_state) { - UID last_uid = 0; // NOT SURE ? - - for(uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) { - double camera_x = 2 * (double)x / SCREEN_WIDTH - 1; - double ray_x = plugin_state->player.dir.x + plugin_state->player.plane.x * camera_x; - double ray_y = plugin_state->player.dir.y + plugin_state->player.plane.y * camera_x; - uint8_t map_x = (uint8_t)plugin_state->player.pos.x; - uint8_t map_y = (uint8_t)plugin_state->player.pos.y; - Coords map_coords = {plugin_state->player.pos.x, plugin_state->player.pos.y}; - double delta_x = fabs(1 / ray_x); - double delta_y = fabs(1 / ray_y); - - int8_t step_x; - int8_t step_y; - double side_x; - double side_y; - - if(ray_x < 0) { - step_x = -1; - side_x = (plugin_state->player.pos.x - map_x) * delta_x; - } else { - step_x = 1; - side_x = (map_x + (double)1.0 - plugin_state->player.pos.x) * delta_x; - } - - if(ray_y < 0) { - step_y = -1; - side_y = (plugin_state->player.pos.y - map_y) * delta_y; - } else { - step_y = 1; - side_y = (map_y + (double)1.0 - plugin_state->player.pos.y) * delta_y; - } - - // Wall detection - uint8_t depth = 0; - bool hit = 0; - bool side; - while(!hit && depth < MAX_RENDER_DEPTH) { - if(side_x < side_y) { - side_x += delta_x; - map_x += step_x; - side = 0; - } else { - side_y += delta_y; - map_y += step_y; - side = 1; - } - - uint8_t block = getBlockAt(level, map_x, map_y); - - if(block == E_WALL) { - hit = 1; - } else { - // Spawning entities here, as soon they are visible for the - // player. Not the best place, but would be a very performance - // cost scan for them in another loop - if(block == E_ENEMY || (block & 0b00001000) /* all collectable items */) { - // Check that it's close to the player - if(coords_distance(&(plugin_state->player.pos), &map_coords) < - MAX_ENTITY_DISTANCE) { - UID uid = create_uid(block, map_x, map_y); - if(last_uid != uid && !isSpawned(uid, plugin_state)) { - spawnEntity(block, map_x, map_y, plugin_state); - last_uid = uid; - } - } - } - } - - depth++; - } - - if(hit) { - double distance; - - if(side == 0) { - distance = - fmax(1, (map_x - plugin_state->player.pos.x + (1 - step_x) / 2) / ray_x); - } else { - distance = - fmax(1, (map_y - plugin_state->player.pos.y + (1 - step_y) / 2) / ray_y); - } - - // store zbuffer value for the column - zbuffer[x / Z_RES_DIVIDER] = fmin(distance * DISTANCE_MULTIPLIER, 255); - - // rendered line height - uint8_t line_height = RENDER_HEIGHT / distance; - - drawVLine( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (int)distance / MAX_RENDER_DEPTH * GRADIENT_COUNT - side * 2, - canvas); - } - } -} - -// Sort entities from far to close -uint8_t sortEntities(PluginState* const plugin_state) { - uint8_t gap = plugin_state->num_entities; - bool swapped = false; - while(gap > 1 || swapped) { - //shrink factor 1.3 - gap = (gap * 10) / 13; - if(gap == 9 || gap == 10) gap = 11; - if(gap < 1) gap = 1; - swapped = false; - for(uint8_t i = 0; i < plugin_state->num_entities - gap; i++) { - uint8_t j = i + gap; - if(plugin_state->entity[i].distance < plugin_state->entity[j].distance) { - swap(plugin_state->entity[i], plugin_state->entity[j]); - swapped = true; - } - } - } - return swapped; -} - -Coords translateIntoView(Coords* pos, PluginState* const plugin_state) { - //translate sprite position to relative to camera - double sprite_x = pos->x - plugin_state->player.pos.x; - double sprite_y = pos->y - plugin_state->player.pos.y; - - //required for correct matrix multiplication - double inv_det = - ((double)1.0 / - ((double)plugin_state->player.plane.x * (double)plugin_state->player.dir.y - - (double)plugin_state->player.dir.x * (double)plugin_state->player.plane.y)); - double transform_x = - inv_det * (plugin_state->player.dir.y * sprite_x - plugin_state->player.dir.x * sprite_y); - double transform_y = inv_det * (-plugin_state->player.plane.y * sprite_x + - plugin_state->player.plane.x * sprite_y); // Z in screen - Coords res = {transform_x, transform_y}; - return res; -} - -void renderEntities(double view_height, Canvas* const canvas, PluginState* const plugin_state) { - sortEntities(plugin_state); - - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - if(plugin_state->entity[i].state == S_HIDDEN) continue; - - Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state); - - // don´t render if behind the player or too far away - if(transform.y <= (double)0.1 || transform.y > MAX_SPRITE_DEPTH) { - continue; - } - - int16_t sprite_screen_x = HALF_WIDTH * ((double)1.0 + transform.x / transform.y); - int8_t sprite_screen_y = RENDER_HEIGHT / 2 + view_height / transform.y; - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - // don´t try to render if outside of screen - // doing this pre-shortcut due int16 -> int8 conversion makes out-of-screen - // values fit into the screen space - if(sprite_screen_x < -HALF_WIDTH || sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH) { - continue; - } - - switch(type) { - case E_ENEMY: { - uint8_t sprite; - if(plugin_state->entity[i].state == S_ALERT) { - // walking - sprite = ((int)furi_get_tick() / 500) % 2; - } else if(plugin_state->entity[i].state == S_FIRING) { - // fireball - sprite = 2; - } else if(plugin_state->entity[i].state == S_HIT) { - // hit - sprite = 3; - } else if(plugin_state->entity[i].state == S_MELEE) { - // melee atack - sprite = plugin_state->entity[i].timer > 10 ? 2 : 1; - } else if(plugin_state->entity[i].state == S_DEAD) { - // dying - sprite = plugin_state->entity[i].timer > 0 ? 3 : 4; - } else { - // stand - sprite = 0; - } - - drawSprite( - sprite_screen_x - BMP_IMP_WIDTH * (double).5 / transform.y, - sprite_screen_y - 8 / transform.y, - imp_inv, - imp_mask_inv, - BMP_IMP_WIDTH, - BMP_IMP_HEIGHT, - sprite, - transform.y, - canvas); - break; - } - - case E_FIREBALL: { - drawSprite( - sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, - sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, - fireball, - fireball_mask, - BMP_FIREBALL_WIDTH, - BMP_FIREBALL_HEIGHT, - 0, - transform.y, - canvas); - break; - } - - case E_MEDIKIT: { - drawSprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - item, - item_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 0, - transform.y, - canvas); - break; - } - - case E_KEY: { - drawSprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - item, - item_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 1, - transform.y, - canvas); - break; - } - } - } -} - -void renderGun(uint8_t gun_pos, double amount_jogging, Canvas* const canvas) { - // jogging - char x = 48 + sin((double)furi_get_tick() * (double)JOGGING_SPEED) * 10 * amount_jogging; - char y = RENDER_HEIGHT - gun_pos + - fabs(cos((double)furi_get_tick() * (double)JOGGING_SPEED)) * 8 * amount_jogging; - - if(gun_pos > GUN_SHOT_POS - 2) { - // Gun fire - drawBitmap(x + 6, y - 11, &I_fire_inv, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1, canvas); - } - - // Don't draw over the hud! - uint8_t clip_height = fmax(0, fmin(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); - - // Draw the gun (black mask + actual sprite). - drawBitmap(x, y, &I_gun_mask_inv, BMP_GUN_WIDTH, clip_height, 0, canvas); - drawBitmap(x, y, &I_gun_inv, BMP_GUN_WIDTH, clip_height, 1, canvas); - //drawGun(x,y,gun_mask, BMP_GUN_WIDTH, clip_height, 0, canvas); - //drawGun(x,y,gun, BMP_GUN_WIDTH, clip_height, 1, canvas); -} - -// Only needed first time -void renderHud(Canvas* const canvas, PluginState* plugin_state) { - drawTextSpace(2, 58, "{}", 0, canvas); // Health symbol - drawTextSpace(40, 58, "[]", 0, canvas); // Keys symbol - updateHud(canvas, plugin_state); -} - -// Render values for the HUD -void updateHud(Canvas* const canvas, PluginState* plugin_state) { - clearRect(12, 58, 15, 6, canvas); - clearRect(50, 58, 15, 6, canvas); - drawText(12, 58, plugin_state->player.health, canvas); - drawText(50, 58, plugin_state->player.keys, canvas); -} - -// Debug stats -void renderStats(Canvas* const canvas, PluginState* plugin_state) { - clearRect(58, 58, 70, 6, canvas); - drawText(114, 58, (int)getActualFps(), canvas); - drawText(82, 58, plugin_state->num_entities, canvas); - // drawText(94, 58, freeMemory()); -} - -// Intro screen -void loopIntro(Canvas* const canvas) { - canvas_draw_icon(canvas, 0, 0, &I_logo_inv); - //drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, "PRESS FIRE", 1, canvas); -} - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - canvas_set_font(canvas, FontPrimary); - - switch(plugin_state->scene) { - case INTRO: { - loopIntro(canvas); - break; - } - case GAME_PLAY: { - updateEntities(sto_level_1, canvas, plugin_state); - - renderGun(plugin_state->gun_pos, plugin_state->jogging, canvas); - renderMap(sto_level_1, plugin_state->view_height, canvas, plugin_state); - - renderEntities(plugin_state->view_height, canvas, plugin_state); - - renderHud(canvas, plugin_state); - updateHud(canvas, plugin_state); - renderStats(canvas, plugin_state); - break; - } - } - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void doom_state_init(PluginState* const plugin_state) { - plugin_state->notify = furi_record_open(RECORD_NOTIFICATION); - plugin_state->num_entities = 0; - plugin_state->num_static_entities = 0; - - plugin_state->scene = INTRO; - plugin_state->gun_pos = 0; - plugin_state->view_height = 0; - plugin_state->init = true; - - plugin_state->up = false; - plugin_state->down = false; - plugin_state->left = false; - plugin_state->right = false; - plugin_state->fired = false; - plugin_state->gun_fired = false; -#ifdef SOUND - - plugin_state->music_instance = malloc(sizeof(MusicPlayer)); - plugin_state->music_instance->model = malloc(sizeof(MusicPlayerModel)); - memset( - plugin_state->music_instance->model->duration_history, - 0xff, - MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - memset( - plugin_state->music_instance->model->semitone_history, - 0xff, - MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - plugin_state->music_instance->model->volume = 2; - - plugin_state->music_instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - //plugin_state->music_instance->view_port = view_port_alloc(); - - plugin_state->music_instance->worker = music_player_worker_alloc(); - //music_player_worker_set_volume(plugin_state->music_instance->worker, 0.75); - music_player_worker_set_volume( - plugin_state->music_instance->worker, - MUSIC_PLAYER_VOLUMES[plugin_state->music_instance->model->volume]); - plugin_state->intro_sound = true; - //init_sound(plugin_state->music_instance); -#endif -} - -static void doom_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void doom_game_tick(PluginState* const plugin_state) { - if(plugin_state->scene == GAME_PLAY) { - //fps(); - //player is alive - if(plugin_state->player.health > 0) { - if(plugin_state->up) { - plugin_state->player.velocity += - ((double)MOV_SPEED - plugin_state->player.velocity) * (double).4; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - //plugin_state->up = false; - } else if(plugin_state->down) { - plugin_state->player.velocity += - (-(double)MOV_SPEED - plugin_state->player.velocity) * (double).4; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - //plugin_state->down = false; - } else { - plugin_state->player.velocity *= (double).5; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - } - - if(plugin_state->right) { - plugin_state->rot_speed = (double)ROT_SPEED * delta; - plugin_state->old_dir_x = plugin_state->player.dir.x; - plugin_state->player.dir.x = - plugin_state->player.dir.x * cos(-(plugin_state->rot_speed)) - - plugin_state->player.dir.y * sin(-(plugin_state->rot_speed)); - plugin_state->player.dir.y = - plugin_state->old_dir_x * sin(-(plugin_state->rot_speed)) + - plugin_state->player.dir.y * cos(-(plugin_state->rot_speed)); - plugin_state->old_plane_x = plugin_state->player.plane.x; - plugin_state->player.plane.x = - plugin_state->player.plane.x * cos(-(plugin_state->rot_speed)) - - plugin_state->player.plane.y * sin(-(plugin_state->rot_speed)); - plugin_state->player.plane.y = - plugin_state->old_plane_x * sin(-(plugin_state->rot_speed)) + - plugin_state->player.plane.y * cos(-(plugin_state->rot_speed)); - - //plugin_state->right = false; - } else if(plugin_state->left) { - plugin_state->rot_speed = (double)ROT_SPEED * delta; - plugin_state->old_dir_x = plugin_state->player.dir.x; - plugin_state->player.dir.x = - plugin_state->player.dir.x * cos(plugin_state->rot_speed) - - plugin_state->player.dir.y * sin(plugin_state->rot_speed); - plugin_state->player.dir.y = - plugin_state->old_dir_x * sin(plugin_state->rot_speed) + - plugin_state->player.dir.y * cos(plugin_state->rot_speed); - plugin_state->old_plane_x = plugin_state->player.plane.x; - plugin_state->player.plane.x = - plugin_state->player.plane.x * cos(plugin_state->rot_speed) - - plugin_state->player.plane.y * sin(plugin_state->rot_speed); - plugin_state->player.plane.y = - plugin_state->old_plane_x * sin(plugin_state->rot_speed) + - plugin_state->player.plane.y * cos(plugin_state->rot_speed); - //plugin_state->left = false; - } - plugin_state->view_height = - fabs(sin((double)furi_get_tick() * (double)JOGGING_SPEED)) * 6 * - plugin_state->jogging; - - if(plugin_state->gun_pos > GUN_TARGET_POS) { - // Right after fire - plugin_state->gun_pos -= 1; - } else if(plugin_state->gun_pos < GUN_TARGET_POS) { - plugin_state->gun_pos += 2; - } else if(!plugin_state->gun_fired && plugin_state->fired) { - //furi_hal_speaker_start(20480 / 10, 0.45f); - /*#ifdef SOUND - music_player_worker_start(plugin_state->music_instance->worker); -#endif*/ - plugin_state->gun_pos = GUN_SHOT_POS; - plugin_state->gun_fired = true; - plugin_state->fired = false; - fire(plugin_state); - - } else if(plugin_state->gun_fired && !plugin_state->fired) { - //furi_hal_speaker_stop(); - plugin_state->gun_fired = false; - - notification_message(plugin_state->notify, &sequence_short_sound); - - /*#ifdef SOUND - music_player_worker_stop(plugin_state->music_instance->worker); -#endif*/ - } - } else { - // Player is dead - if(plugin_state->view_height > -10) plugin_state->view_height--; - if(plugin_state->gun_pos > 1) plugin_state->gun_pos -= 2; - } - - if(fabs(plugin_state->player.velocity) > (double)0.003) { - updatePosition( - sto_level_1, - &(plugin_state->player.pos), - plugin_state->player.dir.x * plugin_state->player.velocity * delta, - plugin_state->player.dir.y * plugin_state->player.velocity * delta, - false, - plugin_state); - } else { - plugin_state->player.velocity = 0; - } - } -} - -int32_t doom_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - PluginState* plugin_state = malloc(sizeof(PluginState)); - doom_state_init(plugin_state); - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("Doom_game", "cannot create mutex\r\n"); - furi_record_close(RECORD_NOTIFICATION); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - FuriTimer* timer = - furi_timer_alloc(doom_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 12); - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - ////////////////////////////////// - plugin_state->init = false; - - PluginEvent event; -#ifdef SOUND - music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro); - music_player_worker_start(plugin_state->music_instance->worker); -#endif - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); -#ifdef SOUND - furi_check( - furi_mutex_acquire(plugin_state->music_instance->model_mutex, FuriWaitForever) == - FuriStatusOk); -#endif - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.key == InputKeyBack) { - processing = false; -#ifdef SOUND - if(plugin_state->intro_sound) { - furi_mutex_release(plugin_state->music_instance->model_mutex); - music_player_worker_stop(plugin_state->music_instance->worker); - } -#endif - } - - if(event.input.type == InputTypePress) { - if(plugin_state->scene == INTRO && event.input.key == InputKeyOk) { - plugin_state->scene = GAME_PLAY; - initializeLevel(sto_level_1, plugin_state); -#ifdef SOUND - furi_mutex_release(plugin_state->music_instance->model_mutex); - music_player_worker_stop(plugin_state->music_instance->worker); - plugin_state->intro_sound = false; -#endif - goto skipintro; - } - - //While playing game - if(plugin_state->scene == GAME_PLAY) { - // If the player is alive - if(plugin_state->player.health > 0) { - //Player speed - if(event.input.key == InputKeyUp) { - plugin_state->up = true; - } else if(event.input.key == InputKeyDown) { - plugin_state->down = true; - } - // Player rotation - if(event.input.key == InputKeyRight) { - plugin_state->right = true; - } else if(event.input.key == InputKeyLeft) { - plugin_state->left = true; - } - if(event.input.key == InputKeyOk) { - /*#ifdef SOUND - music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dspistol); -#endif*/ - if(plugin_state->fired) { - plugin_state->fired = false; - } else { - plugin_state->fired = true; - } - } - } else { - // Player is dead - if(event.input.key == InputKeyOk) plugin_state->scene = INTRO; - } - } - } - if(event.input.type == InputTypeRelease) { - if(plugin_state->player.health > 0) { - //Player speed - if(event.input.key == InputKeyUp) { - plugin_state->up = false; - } else if(event.input.key == InputKeyDown) { - plugin_state->down = false; - } - // Player rotation - if(event.input.key == InputKeyRight) { - plugin_state->right = false; - } else if(event.input.key == InputKeyLeft) { - plugin_state->left = false; - } - } - } - } - - skipintro: - if(event.type == EventTypeTick) { - doom_game_tick(plugin_state); - } - } -#ifdef SOUND - furi_mutex_release(plugin_state->music_instance->model_mutex); -#endif - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } -#ifdef SOUND - music_player_worker_free(plugin_state->music_instance->worker); - furi_mutex_free(plugin_state->music_instance->model_mutex); - free(plugin_state->music_instance->model); - free(plugin_state->music_instance); -#endif - furi_record_close(RECORD_NOTIFICATION); - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(plugin_state->mutex); - furi_message_queue_free(event_queue); - free(plugin_state); - return 0; -} diff --git a/applications/external/doom/doom_10px.png b/applications/external/doom/doom_10px.png deleted file mode 100644 index 17fe22c87..000000000 Binary files a/applications/external/doom/doom_10px.png and /dev/null differ diff --git a/applications/external/doom/doom_music_player_worker.c b/applications/external/doom/doom_music_player_worker.c deleted file mode 100644 index e81549625..000000000 --- a/applications/external/doom/doom_music_player_worker.c +++ /dev/null @@ -1,504 +0,0 @@ -#include "doom_music_player_worker.h" - -#include -#include - -#include -#include - -#include - -#define TAG "MusicPlayerWorker" - -#define MUSIC_PLAYER_FILETYPE "Flipper Music Format" -#define MUSIC_PLAYER_VERSION 0 - -#define SEMITONE_PAUSE 0xFF - -#define NOTE_C4 261.63f -#define NOTE_C4_SEMITONE (4.0f * 12.0f) -#define TWO_POW_TWELTH_ROOT 1.059463094359f - -typedef struct { - uint8_t semitone; - uint8_t duration; - uint8_t dots; -} NoteBlock; - -ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST); - -struct MusicPlayerWorker { - FuriThread* thread; - bool should_work; - - MusicPlayerWorkerCallback callback; - void* callback_context; - - float volume; - uint32_t bpm; - uint32_t duration; - uint32_t octave; - NoteBlockArray_t notes; -}; - -static int32_t music_player_worker_thread_callback(void* context) { - furi_assert(context); - MusicPlayerWorker* instance = context; - - NoteBlockArray_it_t it; - NoteBlockArray_it(it, instance->notes); - if(furi_hal_speaker_acquire(1000)) { - while(instance->should_work) { - if(NoteBlockArray_end_p(it)) { - NoteBlockArray_it(it, instance->notes); - furi_delay_ms(10); - } else { - NoteBlock* note_block = NoteBlockArray_ref(it); - - float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE; - float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4); - float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / - note_block->duration; - uint32_t dots = note_block->dots; - while(dots > 0) { - duration += duration / 2; - dots--; - } - uint32_t next_tick = furi_get_tick() + duration; - float volume = instance->volume; - - if(instance->callback) { - instance->callback( - note_block->semitone, - note_block->dots, - note_block->duration, - 0.0, - instance->callback_context); - } - - furi_hal_speaker_stop(); - furi_hal_speaker_start(frequency, volume); - while(instance->should_work && furi_get_tick() < next_tick) { - volume *= 0.9945679; - furi_hal_speaker_set_volume(volume); - furi_delay_ms(2); - } - NoteBlockArray_next(it); - } - } - - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } else { - FURI_LOG_E(TAG, "Speaker system is busy with another process."); - } - - return 0; -} - -MusicPlayerWorker* music_player_worker_alloc() { - MusicPlayerWorker* instance = malloc(sizeof(MusicPlayerWorker)); - - NoteBlockArray_init(instance->notes); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "MusicPlayerWorker"); - furi_thread_set_stack_size(instance->thread, 1024); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, music_player_worker_thread_callback); - - instance->volume = 1.0f; - - return instance; -} - -void music_player_worker_free(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_thread_free(instance->thread); - NoteBlockArray_clear(instance->notes); - free(instance); -} - -static bool is_digit(const char c) { - return isdigit(c) != 0; -} - -static bool is_letter(const char c) { - return islower(c) != 0 || isupper(c) != 0; -} - -static bool is_space(const char c) { - return c == ' ' || c == '\t'; -} - -static size_t extract_number(const char* string, uint32_t* number) { - size_t ret = 0; - while(is_digit(*string)) { - *number *= 10; - *number += (*string - '0'); - string++; - ret++; - } - return ret; -} - -static size_t extract_dots(const char* string, uint32_t* number) { - size_t ret = 0; - while(*string == '.') { - *number += 1; - string++; - ret++; - } - return ret; -} - -static size_t extract_char(const char* string, char* symbol) { - if(is_letter(*string)) { - *symbol = *string; - return 1; - } else { - return 0; - } -} - -static size_t extract_sharp(const char* string, char* symbol) { - if(*string == '#' || *string == '_') { - *symbol = '#'; - return 1; - } else { - return 0; - } -} - -static size_t skip_till(const char* string, const char symbol) { - size_t ret = 0; - while(*string != '\0' && *string != symbol) { - string++; - ret++; - } - if(*string != symbol) { - ret = 0; - } - return ret; -} - -static bool music_player_worker_add_note( - MusicPlayerWorker* instance, - uint8_t semitone, - uint8_t duration, - uint8_t dots) { - NoteBlock note_block; - - note_block.semitone = semitone; - note_block.duration = duration; - note_block.dots = dots; - - NoteBlockArray_push_back(instance->notes, note_block); - - return true; -} - -static int8_t note_to_semitone(const char note) { - switch(note) { - case 'C': - return 0; - // C# - case 'D': - return 2; - // D# - case 'E': - return 4; - case 'F': - return 5; - // F# - case 'G': - return 7; - // G# - case 'A': - return 9; - // A# - case 'B': - return 11; - default: - return 0; - } -} - -static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const char* string) { - const char* cursor = string; - bool result = true; - - while(*cursor != '\0') { - if(!is_space(*cursor)) { - uint32_t duration = 0; - char note_char = '\0'; - char sharp_char = '\0'; - uint32_t octave = 0; - uint32_t dots = 0; - - // Parsing - cursor += extract_number(cursor, &duration); - cursor += extract_char(cursor, ¬e_char); - cursor += extract_sharp(cursor, &sharp_char); - cursor += extract_number(cursor, &octave); - cursor += extract_dots(cursor, &dots); - - // Post processing - note_char = toupper(note_char); - if(!duration) { - duration = instance->duration; - } - if(!octave) { - octave = instance->octave; - } - - // Validation - bool is_valid = true; - is_valid &= (duration >= 1 && duration <= 128); - is_valid &= ((note_char >= 'A' && note_char <= 'G') || note_char == 'P'); - is_valid &= (sharp_char == '#' || sharp_char == '\0'); - is_valid &= (octave <= 16); - is_valid &= (dots <= 16); - if(!is_valid) { - FURI_LOG_E( - TAG, - "Invalid note: %lu%c%c%lu.%lu", - duration, - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots); - result = false; - break; - } - - // Note to semitones - uint8_t semitone = 0; - if(note_char == 'P') { - semitone = SEMITONE_PAUSE; - } else { - semitone += octave * 12; - semitone += note_to_semitone(note_char); - semitone += sharp_char == '#' ? 1 : 0; - } - - if(music_player_worker_add_note(instance, semitone, duration, dots)) { - FURI_LOG_D( - TAG, - "Added note: %c%c%lu.%lu = %u %lu", - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots, - semitone, - duration); - } else { - FURI_LOG_E( - TAG, - "Invalid note: %c%c%lu.%lu = %u %lu", - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots, - semitone, - duration); - } - cursor += skip_till(cursor, ','); - } - - if(*cursor != '\0') cursor++; - } - - return result; -} - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool ret = false; - if(strcasestr(file_path, ".fmf")) { - ret = music_player_worker_load_fmf_from_file(instance, file_path); - } else { - ret = music_player_worker_load_rtttl_from_file(instance, file_path); - } - return ret; -} - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool result = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); - - do { - if(!flipper_format_file_open_existing(file, file_path)) break; - - uint32_t version = 0; - if(!flipper_format_read_header(file, temp_str, &version)) break; - if(furi_string_cmp_str(temp_str, MUSIC_PLAYER_FILETYPE) || - (version != MUSIC_PLAYER_VERSION)) { - FURI_LOG_E(TAG, "Incorrect file format or version"); - break; - } - - if(!flipper_format_read_uint32(file, "BPM", &instance->bpm, 1)) { - FURI_LOG_E(TAG, "BPM is missing"); - break; - } - if(!flipper_format_read_uint32(file, "Duration", &instance->duration, 1)) { - FURI_LOG_E(TAG, "Duration is missing"); - break; - } - if(!flipper_format_read_uint32(file, "Octave", &instance->octave, 1)) { - FURI_LOG_E(TAG, "Octave is missing"); - break; - } - - if(!flipper_format_read_string(file, "Notes", temp_str)) { - FURI_LOG_E(TAG, "Notes is missing"); - break; - } - - if(!music_player_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { - break; - } - - result = true; - } while(false); - - furi_record_close(RECORD_STORAGE); - flipper_format_free(file); - furi_string_free(temp_str); - - return result; -} - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool result = false; - FuriString* content; - content = furi_string_alloc(); - Storage* storage = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(storage); - - do { - if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_E(TAG, "Unable to open file"); - break; - }; - - uint16_t ret = 0; - do { - uint8_t buffer[65] = {0}; - ret = storage_file_read(file, buffer, sizeof(buffer) - 1); - for(size_t i = 0; i < ret; i++) { - furi_string_push_back(content, buffer[i]); - } - } while(ret > 0); - - furi_string_trim(content); - if(!furi_string_size(content)) { - FURI_LOG_E(TAG, "Empty file"); - break; - } - - if(!music_player_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { - FURI_LOG_E(TAG, "Invalid file content"); - break; - } - - result = true; - } while(0); - - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - furi_string_free(content); - - return result; -} - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string) { - furi_assert(instance); - - const char* cursor = string; - - // Skip name - cursor += skip_till(cursor, ':'); - if(*cursor != ':') { - return false; - } - - // Duration - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->duration); - - // Octave - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->octave); - - // BPM - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->bpm); - - // Notes - cursor += skip_till(cursor, ':'); - if(*cursor != ':') { - return false; - } - cursor++; - if(!music_player_worker_parse_notes(instance, cursor)) { - return false; - } - - return true; -} - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context) { - furi_assert(instance); - instance->callback = callback; - instance->callback_context = context; -} - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume) { - furi_assert(instance); - instance->volume = volume; -} - -void music_player_worker_start(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_assert(instance->should_work == false); - - instance->should_work = true; - furi_thread_start(instance->thread); -} - -void music_player_worker_stop(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_assert(instance->should_work == true); - - instance->should_work = false; - furi_thread_join(instance->thread); -} diff --git a/applications/external/doom/doom_music_player_worker.h b/applications/external/doom/doom_music_player_worker.h deleted file mode 100644 index 9958a9273..000000000 --- a/applications/external/doom/doom_music_player_worker.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*MusicPlayerWorkerCallback)( - uint8_t semitone, - uint8_t dots, - uint8_t duration, - float position, - void* context); - -typedef struct MusicPlayerWorker MusicPlayerWorker; - -MusicPlayerWorker* music_player_worker_alloc(); - -void music_player_worker_free(MusicPlayerWorker* instance); - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string); - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context); - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume); - -void music_player_worker_start(MusicPlayerWorker* instance); - -void music_player_worker_stop(MusicPlayerWorker* instance); - -#ifdef __cplusplus -} -#endif diff --git a/applications/external/doom/entities.c b/applications/external/doom/entities.c deleted file mode 100644 index 86c7f6ae1..000000000 --- a/applications/external/doom/entities.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "entities.h" - -//extern "C" -/*Player create_player(double x, double y){ - return {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0}; -}*/ - -Player create_player(double x, double y) { - Player p; - p.pos = create_coords((double)x + (double)0.5, (double)y + (double)0.5); - p.dir = create_coords(1, 0); - p.plane = create_coords(0, -0.66); - p.velocity = 0; - p.health = 100; - p.keys = 0; - return p; //{create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0}; -} - -//extern "C" -Entity - create_entity(uint8_t type, uint8_t x, uint8_t y, uint8_t initialState, uint8_t initialHealth) { - UID uid = create_uid(type, x, y); - Coords pos = create_coords((double)x + (double).5, (double)y + (double).5); - Entity new_entity; // = { uid, pos, initialState, initialHealth, 0, 0 }; - new_entity.uid = uid; - new_entity.pos = pos; - new_entity.state = initialState; - new_entity.health = initialHealth; - new_entity.distance = 0; - new_entity.timer = 0; - return new_entity; -} - -//extern "C" -StaticEntity crate_static_entity(UID uid, uint8_t x, uint8_t y, bool active) { - StaticEntity ent; - ent.uid = uid; - ent.x = x; - ent.y = y; - ent.active = active; - return ent; -} \ No newline at end of file diff --git a/applications/external/doom/entities.h b/applications/external/doom/entities.h deleted file mode 100644 index ef5eb1a78..000000000 --- a/applications/external/doom/entities.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _entities_h -#define _entities_h -#include -#include -#include "types.h" - -// Shortcuts -//#define create_player(x, y) {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100} - -#define create_enemy(x, y) create_entity(E_ENEMY, x, y, S_STAND, 50) -#define create_medikit(x, y) create_entity(E_MEDIKIT, x, y, S_STAND, 0) -#define create_key(x, y) create_entity(E_KEY, x, y, S_STAND, 0) -#define create_fireball(x, y, dir) create_entity(E_FIREBALL, x, y, S_STAND, dir) -#define create_door(x, y) create_entity(E_DOOR, x, y, S_STAND, 0) - -// entity statuses -#define S_STAND 0 -#define S_ALERT 1 -#define S_FIRING 2 -#define S_MELEE 3 -#define S_HIT 4 -#define S_DEAD 5 -#define S_HIDDEN 6 -#define S_OPEN 7 -#define S_CLOSE 8 - -typedef struct Player { - Coords pos; - Coords dir; - Coords plane; - double velocity; - uint8_t health; - uint8_t keys; -} Player; - -typedef struct Entity { - UID uid; - Coords pos; - uint8_t state; - uint8_t health; // angle for fireballs - uint8_t distance; - uint8_t timer; -} Entity; - -typedef struct StaticEntity { - UID uid; - uint8_t x; - uint8_t y; - bool active; -} StaticEntity; - -Entity - create_entity(uint8_t type, uint8_t x, uint8_t y, uint8_t initialState, uint8_t initialHealth); -StaticEntity create_static_entity(UID uid, uint8_t x, uint8_t y, bool active); -Player create_player(double x, double y); -#endif diff --git a/applications/external/doom/level.h b/applications/external/doom/level.h deleted file mode 100644 index 4d92a1cc6..000000000 --- a/applications/external/doom/level.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef _level_h -#define _level_h - -#include "constants.h" - -/* - Based on E1M1 from Wolfenstein 3D - - ################################################################ - #############################...........######################## - ######....###################........E..######################## - ######....########..........#...........#...#################### - ######.....#######..........L.....E.......M.#################### - ######.....#######..........#...........#...#################### - ##################...########...........######################## - ######.........###...########...........######################## - ######.........###...#############D############################# - ######.........#......E##########...############################ - ######....E....D...E...##########...############################ - ######.........#.......##########...############################ - ######....E....##################...############################ - #...##.........##################...############################ - #.K.######D######################...############################ - #...#####...###############...#E.....K########################## - ##D######...###############..####...############################ - #...#####...###############..####...############################ - #...#...#...###############..####...############################ - #...D...#...#####################...############################ - #...#...#...#####################...############################ - #...######D#######################L############################# - #.E.##.........#################.....#################........## - #...##.........############...............############........## - #...##...E.....############...............############........## - #....#.........############...E.......E....#.........#........## - #....L....K....############................D....E....D....E...## - #....#.........############................#.........#........## - #...##.....E...############...............####....####........## - #...##.........############...............#####..#####.....M..## - #...##.........#################.....##########..#####........## - #...######L#######################D############..############### - #...#####...#####################...###########..############### - #E.E#####...#####################...###########..############### - #...#...#...#####################.E.###########..############### - #...D.M.#...#####################...###########..############### - #...#...#...#####################...###########..###.#.#.#.##### - #...#####...#####################...###########...#.........#### - #...#####...#####################...###########...D....E..K.#### - #................##......########...###########...#.........#### - #....E........E...L...E...X######...################.#.#.#.##### - #................##......########...############################ - #################################...############################ - #############..#..#..#############L############################# - ###########....#..#.########....#...#....####################### - #############.....##########.P..D...D....####################### - ############################....#...#....####################### - ##############..#################...############################ - ##############..############....#...#....####################### - ############################....D...D....####################### - ############################....#...#....####################### - #################################...############################ - ############################.............####################### - ############################..........EK.####################### - ############################.............####################### - ################################################################ -*/ - -/* - Same map above built from some regexp replacements using the legend above. - Using this way lets me use only 4 bit to store each block -*/ -const uint8_t sto_level_1[LEVEL_SIZE] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x90, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF2, - 0x00, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0x05, 0x00, 0x00, 0x90, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0xFF, - 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x08, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF2, 0x02, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x40, 0x80, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x40, 0x00, 0x02, 0x00, 0x90, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00, 0x7F, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x29, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -#endif diff --git a/applications/external/doom/sound.h b/applications/external/doom/sound.h deleted file mode 100644 index 514381334..000000000 --- a/applications/external/doom/sound.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef sound_h -#define sound_h -#include -#include -#include -#include "doom_music_player_worker.h" - -//static const char dspistol[] = "AnyConv:d=,o=,b=120:408,40p,40p,40p,40p,405,40p,40p,40p,405,30p.,30p.,30p.,13p"; -static const char dsintro[] = - "Doom:d=32,o=4,b=56:f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,e5,a#,a#,f5,f#5,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,8e5"; -//static const char dsgetpow[] = "dsgetpow:d=,o=,b=120:407,40p,30.6,407,40p,406,40p,407,40p,40p,407,30p.,407"; -//static const char dsnoway[] = "dsnoway:d=,o=,b=120:407,30.4"; - -#define MUSIC_PLAYER_SEMITONE_HISTORY_SIZE 4 -static const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1}; - -typedef struct { - uint8_t semitone_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE]; - uint8_t duration_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE]; - - uint8_t volume; - uint8_t semitone; - uint8_t dots; - uint8_t duration; - float position; -} MusicPlayerModel; - -typedef struct { - MusicPlayerModel* model; - MusicPlayerWorker* worker; - FuriMutex** model_mutex; -} MusicPlayer; - -#endif \ No newline at end of file diff --git a/applications/external/doom/types.c b/applications/external/doom/types.c deleted file mode 100644 index 6b55d56a7..000000000 --- a/applications/external/doom/types.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "types.h" - -/*template -inline T sq(T value) { - return value * value; -}*/ - -double sq(double val) { - return val * val; -} - -//extern "C" -Coords create_coords(double x, double y) { - Coords cord; - cord.x = x; - cord.y = y; - return cord; -} - -//extern "C" -uint8_t coords_distance(Coords* a, Coords* b) { - return sqrt(sq(a->x - b->x) + sq(a->y - b->y)) * 20; -} - -//extern "C" -UID create_uid(uint8_t type, uint8_t x, uint8_t y) { - return ((y << 6) | x) << 4 | type; -} - -//extern "C" -uint8_t uid_get_type(UID uid) { - return uid & 0x0F; -} diff --git a/applications/external/doom/types.h b/applications/external/doom/types.h deleted file mode 100644 index b8579f645..000000000 --- a/applications/external/doom/types.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _types_h -#define _types_h - -#include -#include -//#include "constants.h" - -#define UID_null 0 - -// Entity types (legend applies to level.h) -#define E_FLOOR 0x0 // . (also null) -#define E_WALL 0xF // # -#define E_PLAYER 0x1 // P -#define E_ENEMY 0x2 // E -#define E_DOOR 0x4 // D -#define E_LOCKEDDOOR 0x5 // L -#define E_EXIT 0x7 // X -// collectable entities >= 0x8 -#define E_MEDIKIT 0x8 // M -#define E_KEY 0x9 // K -#define E_FIREBALL 0xA // not in map - -typedef uint16_t UID; -typedef uint8_t EType; - -typedef struct Coords { - double x; - double y; -} Coords; - -UID create_uid(EType type, uint8_t x, uint8_t y); -EType uid_get_type(UID uid); -Coords create_coords(double x, double y); -uint8_t coords_distance(Coords* a, Coords* b); - -#endif diff --git a/applications/external/flappy_bird/application.fam b/applications/external/flappy_bird/application.fam deleted file mode 100644 index 625c5f66c..000000000 --- a/applications/external/flappy_bird/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="flappy_bird", - name="Flappy Bird", - apptype=FlipperAppType.EXTERNAL, - entry_point="flappy_game_app", - requires=["gui"], - stack_size=4 * 1024, - fap_icon="flappy_10px.png", - fap_category="Games", - fap_icon_assets="assets", - fap_author="@DroomOne & @xMasterX", - fap_version="1.0", - fap_description="Flappy Bird Game", -) diff --git a/applications/external/flappy_bird/assets/bird_01.png b/applications/external/flappy_bird/assets/bird_01.png deleted file mode 100644 index 0cd187053..000000000 Binary files a/applications/external/flappy_bird/assets/bird_01.png and /dev/null differ diff --git a/applications/external/flappy_bird/assets/bird_02.png b/applications/external/flappy_bird/assets/bird_02.png deleted file mode 100644 index 3c37cdb8b..000000000 Binary files a/applications/external/flappy_bird/assets/bird_02.png and /dev/null differ diff --git a/applications/external/flappy_bird/assets/bird_03.png b/applications/external/flappy_bird/assets/bird_03.png deleted file mode 100644 index a111ce163..000000000 Binary files a/applications/external/flappy_bird/assets/bird_03.png and /dev/null differ diff --git a/applications/external/flappy_bird/flappy_10px.png b/applications/external/flappy_bird/flappy_10px.png deleted file mode 100644 index d624d3571..000000000 Binary files a/applications/external/flappy_bird/flappy_10px.png and /dev/null differ diff --git a/applications/external/flappy_bird/flappy_bird.c b/applications/external/flappy_bird/flappy_bird.c deleted file mode 100644 index 496ffcf56..000000000 --- a/applications/external/flappy_bird/flappy_bird.c +++ /dev/null @@ -1,379 +0,0 @@ -#include - -#include "flappy_bird_icons.h" -#include -#include -#include -#include -#include - -#define TAG "Flappy" -#define DEBUG false - -#define FLAPPY_BIRD_HEIGHT 15 -#define FLAPPY_BIRD_WIDTH 10 - -#define FLAPPY_PILAR_MAX 6 -#define FLAPPY_PILAR_DIST 35 - -#define FLAPPY_GAB_HEIGHT 25 -#define FLAPPY_GAB_WIDTH 10 - -#define FLAPPY_GRAVITY_JUMP -1.1 -#define FLAPPY_GRAVITY_TICK 0.15 - -#define FLIPPER_LCD_WIDTH 128 -#define FLIPPER_LCD_HEIGHT 64 - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef enum { BirdState0 = 0, BirdState1, BirdState2, BirdStateMAX } BirdState; - -const Icon* bird_states[BirdStateMAX] = { - &I_bird_01, - &I_bird_02, - &I_bird_03, -}; - -typedef struct { - int x; - int y; -} POINT; - -typedef struct { - float gravity; - POINT point; -} BIRD; - -typedef struct { - POINT point; - int height; - int visible; - bool passed; -} PILAR; - -typedef enum { - GameStateLife, - GameStateGameOver, -} State; - -typedef struct { - BIRD bird; - int points; - int pilars_count; - PILAR pilars[FLAPPY_PILAR_MAX]; - bool debug; - State state; - FuriMutex* mutex; -} GameState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -typedef enum { - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -static void flappy_game_random_pilar(GameState* const game_state) { - PILAR pilar; - - pilar.passed = false; - pilar.visible = 1; - pilar.height = random() % (FLIPPER_LCD_HEIGHT - FLAPPY_GAB_HEIGHT) + 1; - pilar.point.y = 0; - pilar.point.x = FLIPPER_LCD_WIDTH + FLAPPY_GAB_WIDTH + 1; - - game_state->pilars_count++; - game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX] = pilar; -} - -static void flappy_game_state_init(GameState* const game_state) { - BIRD bird; - bird.gravity = 0.0f; - bird.point.x = 15; - bird.point.y = 32; - - game_state->debug = DEBUG; - game_state->bird = bird; - game_state->pilars_count = 0; - game_state->points = 0; - game_state->state = GameStateLife; - memset(game_state->pilars, 0, sizeof(game_state->pilars)); - - flappy_game_random_pilar(game_state); -} - -static void flappy_game_state_free(GameState* const game_state) { - free(game_state); -} - -static void flappy_game_tick(GameState* const game_state) { - if(game_state->state == GameStateLife) { - if(!game_state->debug) { - game_state->bird.gravity += FLAPPY_GRAVITY_TICK; - game_state->bird.point.y += game_state->bird.gravity; - } - - // Checking the location of the last respawned pilar. - PILAR* pilar = &game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX]; - if(pilar->point.x == (FLIPPER_LCD_WIDTH - FLAPPY_PILAR_DIST)) - flappy_game_random_pilar(game_state); - - // Updating the position/status of the pilars (visiblity, posotion, game points) - // | | | | | - // | | | | | - // |__| | |__| - // _____X | X_____ - // | | | | | // [Pos + Width of pilar] >= [Bird Pos] - // |_____| | |_____| - // X <----> | X <-> - // Bird Pos + Lenght of the bird] >= [Pilar] - for(int i = 0; i < FLAPPY_PILAR_MAX; i++) { - PILAR* pilar = &game_state->pilars[i]; - if(pilar != NULL && pilar->visible && game_state->state == GameStateLife) { - pilar->point.x--; - if(game_state->bird.point.x >= pilar->point.x + FLAPPY_GAB_WIDTH && - pilar->passed == false) { - pilar->passed = true; - game_state->points++; - } - if(pilar->point.x < -FLAPPY_GAB_WIDTH) pilar->visible = 0; - - 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) { - game_state->bird.point.y = FLIPPER_LCD_HEIGHT - FLAPPY_BIRD_WIDTH; - } - - // Bird inbetween pipes - if((game_state->bird.point.x + FLAPPY_BIRD_HEIGHT >= pilar->point.x) && - (game_state->bird.point.x <= pilar->point.x + FLAPPY_GAB_WIDTH)) { - // Bird below Bottom Pipe - if(game_state->bird.point.y + FLAPPY_BIRD_WIDTH - 2 >= - pilar->height + FLAPPY_GAB_HEIGHT) { - game_state->state = GameStateGameOver; - break; - } - - // Bird above Upper Pipe - if(game_state->bird.point.y < pilar->height) { - game_state->state = GameStateGameOver; - break; - } - } - } - } - } -} - -static void flappy_game_flap(GameState* const game_state) { - game_state->bird.gravity = FLAPPY_GRAVITY_JUMP; -} - -static void flappy_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const GameState* game_state = ctx; - furi_mutex_acquire(game_state->mutex, FuriWaitForever); - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - if(game_state->state == GameStateLife) { - // Pilars - for(int i = 0; i < FLAPPY_PILAR_MAX; i++) { - const PILAR* pilar = &game_state->pilars[i]; - if(pilar != NULL && pilar->visible == 1) { - canvas_draw_frame( - canvas, pilar->point.x, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height); - - canvas_draw_frame( - canvas, pilar->point.x + 1, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height); - - canvas_draw_frame( - canvas, - pilar->point.x + 2, - pilar->point.y, - FLAPPY_GAB_WIDTH - 1, - pilar->height); - - canvas_draw_frame( - canvas, - pilar->point.x, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - - canvas_draw_frame( - canvas, - pilar->point.x + 1, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH - 1, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - - canvas_draw_frame( - canvas, - pilar->point.x + 2, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH - 1, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - } - } - - // Switch animation - BirdState bird_state = BirdState1; - if(game_state->bird.gravity < -0.5) - bird_state = BirdState0; - else if(game_state->bird.gravity > 0.5) - bird_state = BirdState2; - - canvas_draw_icon( - canvas, game_state->bird.point.x, game_state->bird.point.y, bird_states[bird_state]); - - canvas_set_font(canvas, FontSecondary); - char buffer[12]; - snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points); - canvas_draw_str_aligned(canvas, 100, 12, AlignCenter, AlignBottom, buffer); - - if(game_state->debug) { - char coordinates[20]; - snprintf(coordinates, sizeof(coordinates), "Y: %u", game_state->bird.point.y); - canvas_draw_str_aligned(canvas, 1, 12, AlignCenter, AlignBottom, coordinates); - } - } - - if(game_state->state == GameStateGameOver) { - // Screen is 128x64 px - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 37, 31, "Game Over"); - - canvas_set_font(canvas, FontSecondary); - char buffer[12]; - snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); - } - - furi_mutex_release(game_state->mutex); -} - -static void flappy_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void flappy_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t flappy_game_app(void* p) { - UNUSED(p); - int32_t return_code = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - GameState* game_state = malloc(sizeof(GameState)); - flappy_game_state_init(game_state); - - game_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!game_state->mutex) { - FURI_LOG_E(TAG, "cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, flappy_game_render_callback, game_state); - view_port_input_callback_set(view_port, flappy_game_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(flappy_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 25); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(game_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(game_state->state == GameStateLife) { - flappy_game_flap(game_state); - } - - break; - case InputKeyDown: - break; - case InputKeyRight: - break; - case InputKeyLeft: - break; - case InputKeyOk: - if(game_state->state == GameStateGameOver) { - flappy_game_state_init(game_state); - } - - if(game_state->state == GameStateLife) { - flappy_game_flap(game_state); - } - - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - flappy_game_tick(game_state); - } - } - - view_port_update(view_port); - furi_mutex_release(game_state->mutex); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(game_state->mutex); - -free_and_exit: - flappy_game_state_free(game_state); - furi_message_queue_free(event_queue); - - return return_code; -} diff --git a/applications/external/game_of_life/application.fam b/applications/external/game_of_life/application.fam deleted file mode 100644 index a4de9ff40..000000000 --- a/applications/external/game_of_life/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="gameoflife", - name="Game of Life", - apptype=FlipperAppType.EXTERNAL, - entry_point="game_of_life_app", - cdefines=["APP_GAMEOFLIFE_GAME"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="golIcon.png", - fap_category="Games", - fap_author="@tgxn (original by @itsyourbedtime)", - fap_weburl="https://github.com/tgxn/flipperzero-firmware/blob/dev/applications/game_of_life/game_of_life.c", - fap_version="1.0", - fap_description="Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.", -) diff --git a/applications/external/game_of_life/game_of_life.c b/applications/external/game_of_life/game_of_life.c deleted file mode 100644 index 8629062b8..000000000 --- a/applications/external/game_of_life/game_of_life.c +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include - -#include -#include - -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} AppEvent; - -typedef struct { - bool revive; - int evo; - FuriMutex* mutex; -} State; - -unsigned char new[TOTAL_PIXELS] = {}; -unsigned char old[TOTAL_PIXELS] = {}; -unsigned char* fields[] = {new, old}; - -int current = 0; -int next = 1; - -unsigned char get_cell(int x, int y) { - if(x <= 0 || x >= SCREEN_WIDTH) return 0; - if(y <= 0 || y >= SCREEN_HEIGHT) return 0; - - int pix = (y * SCREEN_WIDTH) + x; - return fields[current][pix]; -} - -int count_neightbors(int x, int y) { - return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) + - get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) + - get_cell(x, y + 1); -} - -static void update_field(State* state) { - if(state->revive) { - for(int i = 0; i < TOTAL_PIXELS; ++i) { - if((random() % 100) == 1) { - fields[current][i] = 1; - } - state->revive = false; - } - } - - for(int i = 0; i < TOTAL_PIXELS; ++i) { - int x = i % SCREEN_WIDTH; - int y = (int)(i / SCREEN_WIDTH); - - int v = get_cell(x, y); - int n = count_neightbors(x, y); - - if(v && n == 3) { - ++state->evo; - } else if(v && (n < 2 || n > 3)) { - ++state->evo; - v = 0; - } else if(!v && n == 3) { - ++state->evo; - v = 1; - } - - fields[next][i] = v; - } - - next ^= current; - current ^= next; - next ^= current; - - if(state->evo < TOTAL_PIXELS) { - state->revive = true; - state->evo = 0; - } -} - -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, 0); -} - -static void render_callback(Canvas* canvas, void* ctx) { - //furi_assert(ctx); - State* state = ctx; - furi_mutex_acquire(state->mutex, FuriWaitForever); - - canvas_clear(canvas); - - for(int i = 0; i < TOTAL_PIXELS; ++i) { - int x = i % SCREEN_WIDTH; - int y = (int)(i / SCREEN_WIDTH); - if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y); - } - furi_mutex_release(state->mutex); -} - -int32_t game_of_life_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent)); - furi_check(event_queue); - - State* _state = malloc(sizeof(State)); - - _state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!_state->mutex) { - printf("cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, _state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - AppEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); - furi_mutex_acquire(_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk && event.type == EventTypeKey && - event.input.type == InputTypePress) { - if(event.input.key == InputKeyBack) { - // furiac_exit(NULL); - processing = false; - furi_mutex_release(_state->mutex); - break; - } - } - - update_field(_state); - - view_port_update(view_port); - furi_mutex_release(_state->mutex); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(_state->mutex); - free(_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/game_of_life/golIcon.png b/applications/external/game_of_life/golIcon.png deleted file mode 100644 index df14f812c..000000000 Binary files a/applications/external/game_of_life/golIcon.png and /dev/null differ diff --git a/applications/external/hc_sr04/application.fam b/applications/external/hc_sr04/application.fam deleted file mode 100644 index cbe135194..000000000 --- a/applications/external/hc_sr04/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="hc_sr04", - name="[HC-SR] Dist. Sensor", - apptype=FlipperAppType.EXTERNAL, - entry_point="hc_sr04_app", - requires=[ - "gui", - ], - stack_size=2 * 1024, - fap_icon="dist_sensor10px.png", - fap_category="GPIO", - fap_author="@xMasterX (first implementation by @Sanqui)", - fap_version="1.0", - fap_description="HC-SR(04) Distance sensor reader", -) diff --git a/applications/external/hc_sr04/dist_sensor10px.png b/applications/external/hc_sr04/dist_sensor10px.png deleted file mode 100644 index af9aa7358..000000000 Binary files a/applications/external/hc_sr04/dist_sensor10px.png and /dev/null differ diff --git a/applications/external/hc_sr04/hc_sr04.c b/applications/external/hc_sr04/hc_sr04.c deleted file mode 100644 index 66ffdad30..000000000 --- a/applications/external/hc_sr04/hc_sr04.c +++ /dev/null @@ -1,275 +0,0 @@ -// insired by -// https://github.com/esphome/esphome/blob/ac0d921413c3884752193fe568fa82853f0f99e9/esphome/components/ultrasonic/ultrasonic_sensor.cpp -// Ported and modified by @xMasterX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - NotificationApp* notification; - bool have_5v; - bool measurement_made; - uint32_t echo; // us - float distance; // meters -} PluginState; - -const NotificationSequence sequence_done = { - &message_display_backlight_on, - &message_green_255, - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - // border around the edge of the screen - // canvas_draw_frame(canvas, 0, 0, 128, 64); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned( - canvas, 64, 2, AlignCenter, AlignTop, "HC-SR04 Ultrasonic\nDistance Sensor"); - - canvas_set_font(canvas, FontSecondary); - - if(!plugin_state->have_5v) { - elements_multiline_text_aligned( - canvas, - 4, - 28, - AlignLeft, - AlignTop, - "5V on GPIO must be\nenabled, or USB must\nbe connected."); - } else { - if(!plugin_state->measurement_made) { - elements_multiline_text_aligned( - canvas, 64, 28, AlignCenter, AlignTop, "Press OK button to measure"); - elements_multiline_text_aligned( - canvas, 64, 40, AlignCenter, AlignTop, "13/TX -> Trig\n14/RX -> Echo"); - } else { - elements_multiline_text_aligned(canvas, 4, 28, AlignLeft, AlignTop, "Readout:"); - - FuriString* str_buf; - str_buf = furi_string_alloc(); - furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo); - - canvas_draw_str_aligned( - canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); - furi_string_printf(str_buf, "Distance: %02f m", (double)plugin_state->distance); - canvas_draw_str_aligned( - canvas, 8, 48, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); - - furi_string_free(str_buf); - } - } - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void hc_sr04_state_init(PluginState* const plugin_state) { - plugin_state->echo = -1; - plugin_state->distance = -1; - plugin_state->measurement_made = false; - - furi_hal_power_suppress_charge_enter(); - - plugin_state->have_5v = false; - if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) { - plugin_state->have_5v = true; - } else { - furi_hal_power_enable_otg(); - plugin_state->have_5v = true; - } -} - -float hc_sr04_us_to_m(uint32_t us) { - //speed of sound for 20°C, 50% relative humidity - //331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404 - const float speed_sound_m_per_s = 344.04f; - const float time_s = us / 1e6f; - const float total_dist = time_s * speed_sound_m_per_s; - return total_dist / 2.0f; -} - -static void hc_sr04_measure(PluginState* const plugin_state) { - //plugin_state->echo = 1; - //return; - - if(!plugin_state->have_5v) { - if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) { - plugin_state->have_5v = true; - } else { - return; - } - } - - //furi_hal_light_set(LightRed, 0xFF); - notification_message(plugin_state->notification, &sequence_blink_start_yellow); - - const uint32_t timeout_ms = 2000; - // Pin 13 / TX -> Trig - furi_hal_gpio_write(&gpio_usart_tx, false); - furi_hal_gpio_init(&gpio_usart_tx, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - - // Pin 14 / RX -> Echo - furi_hal_gpio_write(&gpio_usart_rx, false); - furi_hal_gpio_init(&gpio_usart_rx, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); - - //FURI_CRITICAL_ENTER(); - // 10 ms pulse on TX - furi_hal_gpio_write(&gpio_usart_tx, true); - furi_delay_ms(10); - furi_hal_gpio_write(&gpio_usart_tx, false); - - const uint32_t start = furi_get_tick(); - - while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) - ; - while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx)) - ; - - const uint32_t pulse_start = DWT->CYCCNT; - - while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) - ; - const uint32_t pulse_end = DWT->CYCCNT; - - //FURI_CRITICAL_EXIT(); - - plugin_state->echo = - (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); - plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo); - plugin_state->measurement_made = true; - - //furi_hal_light_set(LightRed, 0x00); - notification_message(plugin_state->notification, &sequence_blink_stop); - notification_message(plugin_state->notification, &sequence_done); -} - -int32_t hc_sr04_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - - hc_sr04_state_init(plugin_state); - - furi_hal_console_disable(); - - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("hc_sr04", "cannot create mutex\r\n"); - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_disable_otg(); - } - furi_hal_console_enable(); - furi_hal_power_suppress_charge_exit(); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - - plugin_state->notification = furi_record_open(RECORD_NOTIFICATION); - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_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); - - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - case InputKeyDown: - case InputKeyRight: - case InputKeyLeft: - break; - case InputKeyOk: - hc_sr04_measure(plugin_state); - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_disable_otg(); - } - furi_hal_power_suppress_charge_exit(); - - // Return TX / RX back to usart mode - furi_hal_gpio_init_ex( - &gpio_usart_tx, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn7USART1); - furi_hal_gpio_init_ex( - &gpio_usart_rx, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn7USART1); - furi_hal_console_enable(); - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(plugin_state->mutex); - free(plugin_state); - - return 0; -} diff --git a/applications/external/heap_defence_game/application.fam b/applications/external/heap_defence_game/application.fam deleted file mode 100644 index d19b48ebb..000000000 --- a/applications/external/heap_defence_game/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="heap_defence", - name="Heap Defence", - apptype=FlipperAppType.EXTERNAL, - entry_point="heap_defence_app", - requires=["gui"], - stack_size=1 * 1024, - fap_category="Games", - fap_icon="box.png", - fap_icon_assets="assets_images", - fap_author="@xMasterX (original implementation by @wquinoa & @Vedmein)", - fap_version="1.0", - fap_description="Heap Defence game from hackathon (aka Stack Attack)", -) diff --git a/applications/external/heap_defence_game/assets_images/Background_128x64.png b/applications/external/heap_defence_game/assets_images/Background_128x64.png deleted file mode 100644 index a7eb1326f..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Background_128x64.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box1_10x10.png b/applications/external/heap_defence_game/assets_images/Box1_10x10.png deleted file mode 100644 index d168f9511..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box1_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box2_10x10.png b/applications/external/heap_defence_game/assets_images/Box2_10x10.png deleted file mode 100644 index e3bbb48e7..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box2_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box3_10x10.png b/applications/external/heap_defence_game/assets_images/Box3_10x10.png deleted file mode 100644 index e20e75b00..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box3_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box4_10x10.png b/applications/external/heap_defence_game/assets_images/Box4_10x10.png deleted file mode 100644 index 98d134104..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box4_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box5_10x10.png b/applications/external/heap_defence_game/assets_images/Box5_10x10.png deleted file mode 100644 index f8dbf339f..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box5_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box6p_10x10.png b/applications/external/heap_defence_game/assets_images/Box6p_10x10.png deleted file mode 100644 index da50f8c86..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box6p_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box7p_10x10.png b/applications/external/heap_defence_game/assets_images/Box7p_10x10.png deleted file mode 100644 index efcd2ac0c..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box7p_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Box8p_10x10.png b/applications/external/heap_defence_game/assets_images/Box8p_10x10.png deleted file mode 100644 index 57ca46e9c..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Box8p_10x10.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Game_over_128x64.png b/applications/external/heap_defence_game/assets_images/Game_over_128x64.png deleted file mode 100644 index d4837e635..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Game_over_128x64.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png deleted file mode 100644 index d4837e635..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png deleted file mode 100644 index a88122d90..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png deleted file mode 100644 index 02fa41df0..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png deleted file mode 100644 index d0c63d484..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png deleted file mode 100644 index 1c2756fdb..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png deleted file mode 100644 index 313fd6961..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png deleted file mode 100644 index cf854656c..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate deleted file mode 100644 index b8626c4cf..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate +++ /dev/null @@ -1 +0,0 @@ -4 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png deleted file mode 100644 index 104a779c9..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png deleted file mode 100644 index afc4a932f..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png deleted file mode 100644 index 58c2ef68d..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png deleted file mode 100644 index afee3ec83..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png deleted file mode 100644 index e8bb70be6..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png deleted file mode 100644 index d7dd740f7..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png deleted file mode 100644 index a8a9fe7e7..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png deleted file mode 100644 index d7dd740f7..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png deleted file mode 100644 index fc2150343..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png deleted file mode 100644 index 9a03083a0..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png deleted file mode 100644 index 5c2911fbc..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png deleted file mode 100644 index 9a03083a0..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png deleted file mode 100644 index 7fd2f8627..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_02.png deleted file mode 100644 index 32fc98b74..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_02.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_03.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_03.png deleted file mode 100644 index e7beb004d..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_03.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png deleted file mode 100644 index 32fc98b74..000000000 Binary files a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_rate b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_rate deleted file mode 100644 index 00750edc0..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_rate +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/applications/external/heap_defence_game/assets_images/Person4_1_10x20.png b/applications/external/heap_defence_game/assets_images/Person4_1_10x20.png deleted file mode 100644 index 104a779c9..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Person4_1_10x20.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Person4_2_10x20.png b/applications/external/heap_defence_game/assets_images/Person4_2_10x20.png deleted file mode 100644 index afc4a932f..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Person4_2_10x20.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Person5_1_10x20.png b/applications/external/heap_defence_game/assets_images/Person5_1_10x20.png deleted file mode 100644 index 58c2ef68d..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Person5_1_10x20.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Person5_2_10x20.png b/applications/external/heap_defence_game/assets_images/Person5_2_10x20.png deleted file mode 100644 index afee3ec83..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Person5_2_10x20.png and /dev/null differ diff --git a/applications/external/heap_defence_game/assets_images/Start_128x64.png b/applications/external/heap_defence_game/assets_images/Start_128x64.png deleted file mode 100644 index 32fc98b74..000000000 Binary files a/applications/external/heap_defence_game/assets_images/Start_128x64.png and /dev/null differ diff --git a/applications/external/heap_defence_game/box.png b/applications/external/heap_defence_game/box.png deleted file mode 100644 index 9ad9b3900..000000000 Binary files a/applications/external/heap_defence_game/box.png and /dev/null differ diff --git a/applications/external/heap_defence_game/heap_defence.c b/applications/external/heap_defence_game/heap_defence.c deleted file mode 100644 index 111c22dce..000000000 --- a/applications/external/heap_defence_game/heap_defence.c +++ /dev/null @@ -1,598 +0,0 @@ -// -// Created by moh on 30.11.2021. -// -// Ported to latest firmware by @xMasterX - 18 Oct 2022 -// - -#include - -#include "hede_assets.h" -#include "heap_defence_icons.h" - -#include -#include -#include -#include -#include -#include - -#define Y_FIELD_SIZE 6 -#define Y_LAST (Y_FIELD_SIZE - 1) -#define X_FIELD_SIZE 12 -#define X_LAST (X_FIELD_SIZE - 1) - -#define DRAW_X_OFFSET 4 - -#define TAG "HeDe" - -#define BOX_HEIGHT 10 -#define BOX_WIDTH 10 -#define TIMER_UPDATE_FREQ 8 -#define BOX_GENERATION_RATE 15 - -static IconAnimation* BOX_DESTROYED; -static const Icon* boxes[] = { - (Icon*)&A_HD_BoxDestroyed_10x10, - &I_Box1_10x10, - &I_Box2_10x10, - &I_Box3_10x10, - &I_Box4_10x10, - &I_Box5_10x10}; - -static uint8_t BOX_TEXTURE_COUNT = sizeof(boxes) / sizeof(Icon*); - -typedef enum { - AnimationGameOver = 0, - AnimationPause, - AnimationLeft, - AnimationRight, -} Animations; - -static IconAnimation* animations[4]; - -typedef u_int8_t byte; - -typedef enum { - GameStatusVibro = 1 << 0, - GameStatusInProgress = 1 << 1, -} GameStatuses; - -typedef struct { - uint8_t x; - uint8_t y; -} Position; - -typedef enum { PlayerRising = 1, PlayerFalling = -1, PlayerNothing = 0 } PlayerStates; - -typedef struct { - Position p; - int8_t x_direction; - int8_t j_tick; - int8_t h_tick; - int8_t states; - bool right_frame; -} Person; - -typedef struct { - uint8_t offset : 4; - uint8_t box_id : 3; - uint8_t exists : 1; -} Box; - -static const uint8_t ROW_BYTE_SIZE = sizeof(Box) * X_FIELD_SIZE; - -typedef struct { - Box** field; - Person* person; - Animations animation; - GameStatuses game_status; - FuriMutex* mutex; -} GameState; - -typedef Box** Field; - -typedef enum { EventGameTick, EventKeyPress } EventType; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -/** - * #Construct / Destroy - */ - -static void game_reset_field_and_player(GameState* game) { - ///Reset field - bzero(game->field[0], X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); - - ///Reset person - bzero(game->person, sizeof(Person)); - game->person->p.x = X_FIELD_SIZE / 2; - game->person->p.y = Y_LAST; -} - -static GameState* allocGameState() { - GameState* game = malloc(sizeof(GameState)); - - game->person = malloc(sizeof(Person)); - - game->field = malloc(Y_FIELD_SIZE * sizeof(Box*)); - game->field[0] = malloc(X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); - for(int y = 1; y < Y_FIELD_SIZE; ++y) { - game->field[y] = game->field[0] + (y * X_FIELD_SIZE); - } - game_reset_field_and_player(game); - - game->game_status = GameStatusInProgress; - return game; -} - -static void game_destroy(GameState* game) { - furi_assert(game); - free(game->field[0]); - free(game->field); - free(game); -} - -static void assets_load() { - /// Init animations - animations[AnimationPause] = icon_animation_alloc(&A_HD_start_128x64); - animations[AnimationGameOver] = icon_animation_alloc(&A_HD_game_over_128x64); - animations[AnimationLeft] = icon_animation_alloc(&A_HD_person_left_10x20); - animations[AnimationRight] = icon_animation_alloc(&A_HD_person_right_10x20); - - BOX_DESTROYED = icon_animation_alloc(&A_HD_BoxDestroyed_10x10); - - icon_animation_start(animations[AnimationLeft]); - icon_animation_start(animations[AnimationRight]); -} - -static void assets_clear() { - for(int i = 0; i < 4; ++i) { - icon_animation_stop(animations[i]); - icon_animation_free(animations[i]); - } - icon_animation_free(BOX_DESTROYED); -} - -/** - * Box utils - */ - -static inline bool is_empty(Box* box) { - return !box->exists; -} - -static inline bool has_dropped(Box* box) { - return box->offset == 0; -} - -static Box* get_upper_box(Field field, Position current) { - return (&field[current.y - 1][current.x]); -} - -static Box* get_lower_box(Field field, Position current) { - return (&field[current.y + 1][current.x]); -} - -static Box* get_next_box(Field field, Position current, int x_direction) { - return (&field[current.y][current.x + x_direction]); -} - -static inline void decrement_y_offset_to_zero(Box* n) { - if(n->offset) --n->offset; -} - -static inline void heap_swap(Box* first, Box* second) { - Box temp = *first; - - *first = *second; - *second = temp; -} - -/** - * #Box logic - */ - -static void generate_box(GameState const* game) { - furi_assert(game); - - static byte tick_count = BOX_GENERATION_RATE; - if(tick_count++ != BOX_GENERATION_RATE) { - return; - } - tick_count = 0; - - int x_offset = rand() % X_FIELD_SIZE; - while(game->field[1][x_offset].exists) { - x_offset = rand() % X_FIELD_SIZE; - } - - game->field[1][x_offset].exists = true; - game->field[1][x_offset].offset = BOX_HEIGHT; - game->field[1][x_offset].box_id = (rand() % (BOX_TEXTURE_COUNT - 1)) + 1; -} - -static void drop_box(GameState* game) { - furi_assert(game); - - for(int y = Y_LAST; y > 0; y--) { - for(int x = 0; x < X_FIELD_SIZE; x++) { - Box* current_box = game->field[y] + x; - Box* upper_box = game->field[y - 1] + x; - - if(y == Y_LAST) { - decrement_y_offset_to_zero(current_box); - } - - decrement_y_offset_to_zero(upper_box); - - if(is_empty(current_box) && !is_empty(upper_box) && has_dropped(upper_box)) { - upper_box->offset = BOX_HEIGHT; - heap_swap(current_box, upper_box); - } - } - } -} - -static bool clear_rows(Box** field) { - for(int x = 0; x < X_FIELD_SIZE; ++x) { - if(is_empty(field[Y_LAST] + x) || !has_dropped(field[Y_LAST] + x)) { - return false; - } - } - - memset(field[Y_LAST], 128, ROW_BYTE_SIZE); - return true; -} - -/** - * Input Handling - */ - -static inline bool on_ground(Person* person, Field field) { - return person->p.y == Y_LAST || field[person->p.y + 1][person->p.x].exists; -} - -static void handle_key_presses(Person* person, InputEvent* input, GameState* game) { - switch(input->key) { - case InputKeyUp: - if(person->states == PlayerNothing && on_ground(person, game->field)) { - person->states = PlayerRising; - person->j_tick = 0; - } - break; - case InputKeyLeft: - person->right_frame = false; - if(person->h_tick == 0) { - person->h_tick = 1; - person->x_direction = -1; - } - break; - case InputKeyRight: - person->right_frame = true; - if(person->h_tick == 0) { - person->h_tick = 1; - person->x_direction = 1; - } - break; - case InputKeyOk: - game->game_status &= ~GameStatusInProgress; - game->animation = AnimationPause; - icon_animation_start(animations[AnimationPause]); - default: - break; - } -} - -/** - * #Person logic - */ - -static inline bool ground_box_check(Field field, Position new_position) { - Box* lower_box = get_lower_box(field, new_position); - - bool ground_box_dropped = - (new_position.y == Y_LAST || //Eсли мы и так в самом низу - is_empty(lower_box) || // Ecли снизу пустота - has_dropped(lower_box)); //Eсли бокс снизу допадал - return ground_box_dropped; -} - -static inline bool is_movable(Field field, Position box_pos, int x_direction) { - //TODO::Moжет и не двух, предположение - bool out_of_bounds = box_pos.x == 0 || box_pos.x == X_LAST; - if(out_of_bounds) return false; - bool box_on_top = box_pos.y < 1 || get_upper_box(field, box_pos)->exists; - if(box_on_top) return false; - bool has_next_box = get_next_box(field, box_pos, x_direction)->exists; - if(has_next_box) return false; - - return true; -} - -static bool horizontal_move(Person* person, Field field) { - Position new_position = person->p; - - if(!person->x_direction) return false; - - new_position.x += person->x_direction; - - bool on_edge_column = new_position.x > X_LAST; - if(on_edge_column) return false; - - if(is_empty(&field[new_position.y][new_position.x])) { - bool ground_box_dropped = ground_box_check(field, new_position); - if(ground_box_dropped) { - person->p = new_position; - return true; - } - } else if(is_movable(field, new_position, person->x_direction)) { - *get_next_box(field, new_position, person->x_direction) = - field[new_position.y][new_position.x]; - - field[new_position.y][new_position.x] = (Box){0}; - person->p = new_position; - return true; - } - return false; -} - -void hd_person_set_state(Person* person, PlayerStates state) { - person->states = state; - person->j_tick = 0; -} - -static void person_move(Person* person, Field field) { - /// Left-right logic - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - - if(person->states == PlayerNothing) { - if(!on_ground(person, field)) { - hd_person_set_state(person, PlayerFalling); - } - } else if(person->states == PlayerRising) { - if(person->j_tick++ == 0) { - person->p.y--; - } else if(person->j_tick == 6) { - hd_person_set_state(person, PlayerNothing); - } - - /// Destroy upper box - get_upper_box(field, person->p)->box_id = 0; - field[person->p.y][person->p.x].box_id = 0; - - } else if(person->states == PlayerFalling) { - if(person->j_tick++ == 0) { - if(on_ground(person, field)) { // TODO: Test the bugfix - hd_person_set_state(person, PlayerNothing); - } else { - person->p.y++; - } - } else if(person->j_tick == 5) { - if(on_ground(person, field)) { - hd_person_set_state(person, PlayerNothing); - } else { - hd_person_set_state(person, PlayerFalling); - } - } - } - - switch(person->h_tick) { - case 0: - break; - case 1: - person->h_tick++; - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - bool moved = horizontal_move(person, field); - if(!moved) { - person->h_tick = 0; - person->x_direction = 0; - } - break; - case 5: - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - person->h_tick = 0; - person->x_direction = 0; - break; - default: - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - person->h_tick++; - } -} - -static inline bool is_person_dead(Person* person, Box** field) { - return get_upper_box(field, person->p)->box_id != 0; -} - -/** - * #Callback - */ - -static void draw_box(Canvas* canvas, Box* box, int x, int y) { - if(is_empty(box)) { - return; - } - byte y_screen = y * BOX_HEIGHT - box->offset; - byte x_screen = x * BOX_WIDTH + DRAW_X_OFFSET; - - if(box->box_id == 0) { - canvas_set_bitmap_mode(canvas, true); - icon_animation_start(BOX_DESTROYED); - canvas_draw_icon_animation(canvas, x_screen, y_screen, BOX_DESTROYED); - if(icon_animation_is_last_frame(BOX_DESTROYED)) { - *box = (Box){0}; - icon_animation_stop(BOX_DESTROYED); - } - canvas_set_bitmap_mode(canvas, false); - } else { - canvas_draw_icon(canvas, x_screen, y_screen, boxes[box->box_id]); - } -} - -static void heap_defense_render_callback(Canvas* const canvas, void* mutex) { - furi_assert(mutex); - const GameState* game = mutex; - furi_mutex_acquire(game->mutex, FuriWaitForever); - - ///Draw GameOver or Pause - if(!(game->game_status & GameStatusInProgress)) { - FURI_LOG_W(TAG, "[DAED_DRAW]func: [%s] line: %d ", __FUNCTION__, __LINE__); - - canvas_draw_icon_animation(canvas, 0, 0, animations[game->animation]); - furi_mutex_release(game->mutex); - return; - } - - ///Draw field - canvas_draw_icon(canvas, 0, 0, &I_Background_128x64); - - ///Draw Person - const Person* person = game->person; - IconAnimation* player_animation = person->right_frame ? animations[AnimationRight] : - animations[AnimationLeft]; - - uint8_t x_screen = person->p.x * BOX_WIDTH + DRAW_X_OFFSET; - if(person->h_tick && person->h_tick != 1) { - if(person->right_frame) { - x_screen += (person->h_tick) * 2 - BOX_WIDTH; - } else { - x_screen -= (person->h_tick) * 2 - BOX_WIDTH; - } - } - - uint8_t y_screen = (person->p.y - 1) * BOX_HEIGHT; - if(person->j_tick) { - if(person->states == PlayerRising) { - y_screen += BOX_HEIGHT - (person->j_tick) * 2; - } else if(person->states == PlayerFalling) { - y_screen -= BOX_HEIGHT - (person->j_tick) * 2; - } - } - - canvas_draw_icon_animation(canvas, x_screen, y_screen, player_animation); - - ///Draw Boxes - canvas_set_color(canvas, ColorBlack); - for(int y = 1; y < Y_FIELD_SIZE; ++y) { - for(int x = 0; x < X_FIELD_SIZE; ++x) { - draw_box(canvas, &(game->field[y][x]), x, y); - } - } - - furi_mutex_release(game->mutex); -} - -static void heap_defense_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - if(input_event->type != InputTypePress && input_event->type != InputTypeLong) return; - - furi_assert(event_queue); - GameEvent event = {.type = EventKeyPress, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void heap_defense_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event; - event.type = EventGameTick; - event.input = (InputEvent){0}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t heap_defence_app(void* p) { - UNUSED(p); - - //FURI_LOG_W(TAG, "Heap defence start %d", __LINE__); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - GameState* game = allocGameState(); - - game->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!game->mutex) { - game_destroy(game); - return 1; - } - - assets_load(); - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, heap_defense_render_callback, game); - view_port_input_callback_set(view_port, heap_defense_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(heap_defense_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / TIMER_UPDATE_FREQ); - - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - memset(game->field[Y_LAST], 128, ROW_BYTE_SIZE); - game->person->p.y -= 2; - game->game_status = 0; - game->animation = AnimationPause; - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event = {0}; - while(event.input.key != InputKeyBack) { - if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) { - continue; - } - - furi_mutex_acquire(game->mutex, FuriWaitForever); - - //unset vibration - if(game->game_status & GameStatusVibro) { - notification_message(notification, &sequence_reset_vibro); - game->game_status &= ~GameStatusVibro; - icon_animation_stop(BOX_DESTROYED); - memset(game->field[Y_LAST], 0, ROW_BYTE_SIZE); - } - - if(!(game->game_status & GameStatusInProgress)) { - if(event.type == EventKeyPress && event.input.key == InputKeyOk) { - game->game_status |= GameStatusInProgress; - icon_animation_stop(animations[game->animation]); - } - - } else if(event.type == EventKeyPress) { - handle_key_presses(game->person, &(event.input), game); - } else { // EventGameTick - - drop_box(game); - generate_box(game); - if(clear_rows(game->field)) { - notification_message(notification, &sequence_set_vibro_on); - icon_animation_start(BOX_DESTROYED); - game->game_status |= GameStatusVibro; - } - person_move(game->person, game->field); - - if(is_person_dead(game->person, game->field)) { - game->game_status &= ~GameStatusInProgress; - game->animation = AnimationGameOver; - icon_animation_start(animations[AnimationGameOver]); - game_reset_field_and_player(game); - notification_message(notification, &sequence_error); - } - } - furi_mutex_release(game->mutex); - view_port_update(view_port); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - furi_message_queue_free(event_queue); - assets_clear(); - furi_mutex_free(game->mutex); - game_destroy(game); - - return 0; -} diff --git a/applications/external/heap_defence_game/hede_assets.c b/applications/external/heap_defence_game/hede_assets.c deleted file mode 100644 index f45c0583d..000000000 --- a/applications/external/heap_defence_game/hede_assets.c +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by user on 15.12.2021. -// -#include "hede_assets.h" -#include - -const uint8_t _A_HD_BoxDestroyed_10x10_0[] = { - 0x01, 0x00, 0x10, 0x00, 0x00, 0x1d, 0xa2, 0x01, 0xc8, 0x80, - 0x6d, 0x20, 0x15, 0x08, 0x06, 0x72, 0x01, 0x48, 0x07, 0xa0, -}; -const uint8_t _A_HD_BoxDestroyed_10x10_1[] = { - 0x00, 0x00, 0x00, 0x28, 0x01, 0x4A, 0x00, 0xA8, 0x01, 0x84, 0x00, - 0x22, 0x00, 0x88, 0x00, 0x58, 0x01, 0x22, 0x00, 0x00, 0x00, -}; -const uint8_t _A_HD_BoxDestroyed_10x10_2[] = { - 0x00, 0x00, 0x00, 0x08, 0x01, 0x42, 0x00, 0x09, 0x01, 0x00, 0x02, - 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x21, 0x00, 0x42, 0x02, -}; -const uint8_t* _A_HD_BoxDestroyed_10x10[] = { - _A_HD_BoxDestroyed_10x10_0, - _A_HD_BoxDestroyed_10x10_1, - _A_HD_BoxDestroyed_10x10_2}; -const Icon A_HD_BoxDestroyed_10x10 = { - .width = 10, - .height = 10, - .frame_count = 3, - .frame_rate = 4, - .frames = _A_HD_BoxDestroyed_10x10}; \ No newline at end of file diff --git a/applications/external/heap_defence_game/hede_assets.h b/applications/external/heap_defence_game/hede_assets.h deleted file mode 100644 index 3bcabc59f..000000000 --- a/applications/external/heap_defence_game/hede_assets.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by user on 15.12.2021. -// - -#ifndef HEDE_ASSETS_H -#define HEDE_ASSETS_H -#include - -extern const Icon A_HD_BoxDestroyed_10x10; - -#endif diff --git a/applications/external/ir_scope/application.fam b/applications/external/ir_scope/application.fam deleted file mode 100644 index ceaa629f7..000000000 --- a/applications/external/ir_scope/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="ir_scope", - name="IR Scope", - apptype=FlipperAppType.EXTERNAL, - entry_point="ir_scope_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="ir_scope.png", - fap_category="Infrared", - fap_author="@kallanreed", - fap_version="1.2", - fap_description="App allows to see incoming IR signals.", -) diff --git a/applications/external/ir_scope/ir_scope.c b/applications/external/ir_scope/ir_scope.c deleted file mode 100644 index d56d1c78c..000000000 --- a/applications/external/ir_scope/ir_scope.c +++ /dev/null @@ -1,184 +0,0 @@ -// Author: github.com/kallanreed -#include -#include -#include -#include -#include -#include - -#define TAG "IR Scope" -#define COLS 128 -#define ROWS 8 - -typedef struct { - bool autoscale; - uint16_t us_per_sample; - size_t timings_cnt; - uint32_t* timings; - uint32_t timings_sum; - FuriMutex* mutex; -} IRScopeState; - -static void state_set_autoscale(IRScopeState* state) { - if(state->autoscale) state->us_per_sample = state->timings_sum / (ROWS * COLS); -} - -static void canvas_draw_str_outline(Canvas* canvas, int x, int y, const char* str) { - canvas_set_color(canvas, ColorWhite); - for(int y1 = -1; y1 <= 1; ++y1) - for(int x1 = -1; x1 <= 1; ++x1) canvas_draw_str(canvas, x + x1, y + y1, str); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, x, y, str); -} - -static void render_callback(Canvas* canvas, void* ctx) { - const IRScopeState* state = (IRScopeState*)ctx; - - furi_mutex_acquire(state->mutex, FuriWaitForever); - - canvas_clear(canvas); - canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Draw the signal chart. - bool on = false; - bool done = false; - size_t ix = 0; - int timing_cols = -1; // Count of columns used to draw the current timing - for(size_t row = 0; row < ROWS && !done; ++row) { - for(size_t col = 0; col < COLS && !done; ++col) { - done = ix >= state->timings_cnt; - - if(!done && timing_cols < 0) { - timing_cols = state->timings[ix] / state->us_per_sample; - on = !on; - } - - if(timing_cols == 0) ++ix; - - int y = row * 8 + 7; - canvas_draw_line(canvas, col, y, col, y - (on ? 5 : 0)); - --timing_cols; - } - } - - canvas_set_font(canvas, FontSecondary); - if(state->autoscale) - canvas_draw_str_outline(canvas, 100, 64, "Auto"); - else { - char buf[20]; - snprintf(buf, sizeof(buf), "%uus", state->us_per_sample); - canvas_draw_str_outline(canvas, 100, 64, buf); - } - - furi_mutex_release(state->mutex); -} - -static void input_callback(InputEvent* input_event, void* ctx) { - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -static void ir_received_callback(void* ctx, InfraredWorkerSignal* signal) { - furi_check(signal); - IRScopeState* state = (IRScopeState*)ctx; - - furi_mutex_acquire(state->mutex, FuriWaitForever); - - const uint32_t* timings; - infrared_worker_get_raw_signal(signal, &timings, &state->timings_cnt); - - if(state->timings) { - free(state->timings); - state->timings_sum = 0; - } - - state->timings = malloc(state->timings_cnt * sizeof(uint32_t)); - - // Copy and sum. - for(size_t i = 0; i < state->timings_cnt; ++i) { - state->timings[i] = timings[i]; - state->timings_sum += timings[i]; - } - - state_set_autoscale(state); - - furi_mutex_release(state->mutex); -} - -int32_t ir_scope_app(void* p) { - UNUSED(p); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - furi_check(event_queue); - - if(furi_hal_infrared_is_busy()) { - FURI_LOG_E(TAG, "Infrared is busy."); - return -1; - } - - IRScopeState state = { - .autoscale = false, .us_per_sample = 200, .timings = NULL, .timings_cnt = 0, .mutex = NULL}; - state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!state.mutex) { - FURI_LOG_E(TAG, "Cannot create mutex."); - return -1; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, &state); - 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); - - InfraredWorker* worker = infrared_worker_alloc(); - infrared_worker_rx_enable_signal_decoding(worker, false); - infrared_worker_rx_enable_blink_on_receiving(worker, true); - infrared_worker_rx_set_received_signal_callback(worker, ir_received_callback, &state); - infrared_worker_rx_start(worker); - - InputEvent event; - bool processing = true; - while(processing) { - if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { - if(event.type == InputTypeRelease) { - furi_mutex_acquire(state.mutex, FuriWaitForever); - - if(event.key == InputKeyBack) { - processing = false; - } else if(event.key == InputKeyUp) { - state.us_per_sample = MIN(1000, state.us_per_sample + 25); - state.autoscale = false; - } else if(event.key == InputKeyDown) { - state.us_per_sample = MAX(25, state.us_per_sample - 25); - state.autoscale = false; - } else if(event.key == InputKeyOk) { - state.autoscale = !state.autoscale; - if(state.autoscale) - state_set_autoscale(&state); - else - state.us_per_sample = 200; - } - - furi_mutex_release(state.mutex); - } - } - view_port_update(view_port); - } - - // Clean up. - infrared_worker_rx_stop(worker); - infrared_worker_free(worker); - - if(state.timings) free(state.timings); - - 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); - furi_mutex_free(state.mutex); - - return 0; -} diff --git a/applications/external/ir_scope/ir_scope.png b/applications/external/ir_scope/ir_scope.png deleted file mode 100644 index c0d7eaba0..000000000 Binary files a/applications/external/ir_scope/ir_scope.png and /dev/null differ diff --git a/applications/external/mandelbrot/Mandelbrot.png b/applications/external/mandelbrot/Mandelbrot.png deleted file mode 100644 index 485f70e5c..000000000 Binary files a/applications/external/mandelbrot/Mandelbrot.png and /dev/null differ diff --git a/applications/external/mandelbrot/application.fam b/applications/external/mandelbrot/application.fam deleted file mode 100644 index 7c476ced8..000000000 --- a/applications/external/mandelbrot/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="mandelbrotset", - name="Mandelbrot Set", - apptype=FlipperAppType.EXTERNAL, - entry_point="mandelbrot_app", - cdefines=["APP_MANDELBROT_GAME"], - requires=["gui"], - stack_size=1 * 1024, - fap_icon="Mandelbrot.png", - fap_category="Media", - fap_author="@Possibly-Matt", - fap_weburl="https://github.com/Possibly-Matt", - fap_version="1.0", - fap_description="The Mandelbrot set is the set of all so-called (complex) numbers that meet Mandelbrots simple arithmetic criterion.", -) diff --git a/applications/external/mandelbrot/mandelbrot.c b/applications/external/mandelbrot/mandelbrot.c deleted file mode 100644 index 8bfe36c77..000000000 --- a/applications/external/mandelbrot/mandelbrot.c +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include -#include -#include - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - float xZoom; - float yZoom; - float xOffset; - float yOffset; - float zoom; -} PluginState; - -bool mandelbrot_pixel(int x, int y, float xZoom, float yZoom, float xOffset, float yOffset) { - float ratio = 128.0 / 64.0; - //x0 := scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.00, 0.47)) - float x0 = (((x / 128.0) * ratio * xZoom)) - xOffset; - //y0 := scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1.12, 1.12)) - float y0 = ((y / 64.0) * yZoom) - yOffset; - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - - int iteration = 0; - int max_iteration = 50; - - while(x2 + y2 <= 4.0 && iteration < max_iteration) { - y1 = 2.0 * x1 * y1 + y0; - x1 = x2 - y2 + x0; - x2 = x1 * x1; - y2 = y1 * y1; - iteration++; - } - - if(iteration > 49) { - return true; - } - - return false; -} - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - // border around the edge of the screen - canvas_draw_frame(canvas, 0, 0, 128, 64); - - for(int y = 0; y < 64; y++) { - for(int x = 0; x < 128; x++) { - // did you know if you just pass the indivdiual bits of plugin_state instead of plugin_state - // you dont get any compiler warnings :) - if(mandelbrot_pixel( - x, - y, - plugin_state->xZoom, - plugin_state->yZoom, - plugin_state->xOffset, - plugin_state->yOffset)) { - canvas_draw_dot(canvas, x, y); - } - } - } - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void mandelbrot_state_init(PluginState* const plugin_state) { - plugin_state->xOffset = 3.0; - plugin_state->yOffset = 1.12; - plugin_state->xZoom = 2.47; - plugin_state->yZoom = 2.24; - plugin_state->zoom = 1; // this controls the camera when -} - -int32_t mandelbrot_app(void* p) { - UNUSED(p); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - mandelbrot_state_init(plugin_state); - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("mandelbrot", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_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); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - plugin_state->yOffset += 0.1 / plugin_state->zoom; - break; - case InputKeyDown: - plugin_state->yOffset += -0.1 / plugin_state->zoom; - break; - case InputKeyRight: - plugin_state->xOffset += -0.1 / plugin_state->zoom; - break; - case InputKeyLeft: - plugin_state->xOffset += 0.1 / plugin_state->zoom; - break; - case InputKeyOk: - plugin_state->xZoom -= (2.47 / 10) / plugin_state->zoom; - plugin_state->yZoom -= (2.24 / 10) / plugin_state->zoom; - // used to make camera control finer the more zoomed you are - // this needs to be some sort of curve - plugin_state->zoom += 0.15; - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } - } - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(plugin_state->mutex); - free(plugin_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/paint/application.fam b/applications/external/paint/application.fam deleted file mode 100644 index e5dec6040..000000000 --- a/applications/external/paint/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="paint", - name="Paint", - apptype=FlipperAppType.EXTERNAL, - entry_point="paint_app", - cdefines=["APP_PAINT"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="paintIcon.png", - fap_category="Media", - fap_author="@n-o-T-I-n-s-a-n-e", - fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e", - fap_version="1.0", - fap_description="A basic Paint app, Click Ok to draw dot, hold Ok to enable drawing continuously, hold Back to clear the screen", -) diff --git a/applications/external/paint/paint.c b/applications/external/paint/paint.c deleted file mode 100644 index 0d4124b02..000000000 --- a/applications/external/paint/paint.c +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // Header-file for boolean data-type. - -typedef struct selected_position { - int x; - int y; -} selected_position; - -typedef struct { - FuriMutex* mutex; - selected_position selected; - bool board[32][16]; - bool isDrawing; -} PaintData; - -void paint_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const PaintData* paint_state = ctx; - furi_mutex_acquire(paint_state->mutex, FuriWaitForever); - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - //draw the canvas(32x16) on screen(144x64) using 4x4 tiles - for(int y = 0; y < 16; y++) { - for(int x = 0; x < 32; x++) { - if(paint_state->board[x][y]) { - canvas_draw_box(canvas, x * 4, y * 4, 4, 4); - } - } - } - - //draw cursor as a 4x4 black box with a 2x2 white box inside - canvas_set_color(canvas, ColorBlack); - canvas_draw_box(canvas, paint_state->selected.x * 4, paint_state->selected.y * 4, 4, 4); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box( - canvas, paint_state->selected.x * 4 + 1, paint_state->selected.y * 4 + 1, 2, 2); - - //release the mutex - furi_mutex_release(paint_state->mutex); -} - -void paint_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -int32_t paint_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - PaintData* paint_state = malloc(sizeof(PaintData)); - - paint_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!paint_state->mutex) { - FURI_LOG_E("paint", "cannot create mutex\r\n"); - free(paint_state); - return -1; - } - - // Configure view port - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, paint_draw_callback, paint_state); - view_port_input_callback_set(view_port, paint_input_callback, event_queue); - - // Register view port in GUI - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - //NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - InputEvent event; - - while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - //break out of the loop if the back key is pressed - if(event.type == InputTypeShort && event.key == InputKeyBack) { - break; - } - - //check the key pressed and change x and y accordingly - if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyUp: - paint_state->selected.y -= 1; - break; - case InputKeyDown: - paint_state->selected.y += 1; - break; - case InputKeyLeft: - paint_state->selected.x -= 1; - break; - case InputKeyRight: - paint_state->selected.x += 1; - break; - case InputKeyOk: - paint_state->board[paint_state->selected.x][paint_state->selected.y] = - !paint_state->board[paint_state->selected.x][paint_state->selected.y]; - break; - - default: - break; - } - - //check if cursor position is out of bounds and reset it to the closest position - if(paint_state->selected.x < 0) { - paint_state->selected.x = 0; - } - if(paint_state->selected.x > 31) { - paint_state->selected.x = 31; - } - if(paint_state->selected.y < 0) { - paint_state->selected.y = 0; - } - if(paint_state->selected.y > 15) { - paint_state->selected.y = 15; - } - if(paint_state->isDrawing == true) { - paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; - } - view_port_update(view_port); - } - if(event.key == InputKeyBack && event.type == InputTypeLong) { - paint_state->board[1][1] = true; - for(int y = 0; y < 16; y++) { - for(int x = 0; x < 32; x++) { - paint_state->board[x][y] = false; - } - } - view_port_update(view_port); - } - if(event.key == InputKeyOk && event.type == InputTypeLong) { - paint_state->isDrawing = !paint_state->isDrawing; - paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; - view_port_update(view_port); - } - } - - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(paint_state->mutex); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - free(paint_state); - - return 0; -} diff --git a/applications/external/paint/paintIcon.png b/applications/external/paint/paintIcon.png deleted file mode 100644 index cc0a8b7d8..000000000 Binary files a/applications/external/paint/paintIcon.png and /dev/null differ diff --git a/applications/external/spectrum_analyzer/application.fam b/applications/external/spectrum_analyzer/application.fam deleted file mode 100644 index 13f5d49f9..000000000 --- a/applications/external/spectrum_analyzer/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="spectrum_analyzer", - name="Spectrum Analyzer", - apptype=FlipperAppType.EXTERNAL, - entry_point="spectrum_analyzer_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="spectrum_10px.png", - fap_category="Sub-GHz", - fap_author="@xMasterX & @theY4Kman & @ALEEF02 (original by @jolcese)", - fap_version="1.1", - fap_description="Displays a spectrogram chart to visually represent RF signals around you.", -) diff --git a/applications/external/spectrum_analyzer/helpers/radio_device_loader.c b/applications/external/spectrum_analyzer/helpers/radio_device_loader.c deleted file mode 100644 index d2cffde58..000000000 --- a/applications/external/spectrum_analyzer/helpers/radio_device_loader.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "radio_device_loader.h" - -#include -#include - -static void radio_device_loader_power_on() { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); - } -} - -static void radio_device_loader_power_off() { - if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); -} - -bool radio_device_loader_is_connect_external(const char* name) { - bool is_connect = false; - bool is_otg_enabled = furi_hal_power_is_otg_enabled(); - - if(!is_otg_enabled) { - radio_device_loader_power_on(); - } - - const SubGhzDevice* device = subghz_devices_get_by_name(name); - if(device) { - is_connect = subghz_devices_is_connect(device); - } - - if(!is_otg_enabled) { - radio_device_loader_power_off(); - } - return is_connect; -} - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type) { - const SubGhzDevice* radio_device; - - if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && - radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) { - radio_device_loader_power_on(); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); - subghz_devices_begin(radio_device); - } else if(current_radio_device == NULL) { - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } else { - radio_device_loader_end(current_radio_device); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } - - return radio_device; -} - -void radio_device_loader_end(const SubGhzDevice* radio_device) { - furi_assert(radio_device); - radio_device_loader_power_off(); - if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) { - subghz_devices_end(radio_device); - } -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/helpers/radio_device_loader.h b/applications/external/spectrum_analyzer/helpers/radio_device_loader.h deleted file mode 100644 index bee4e2c36..000000000 --- a/applications/external/spectrum_analyzer/helpers/radio_device_loader.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -/** SubGhzRadioDeviceType */ -typedef enum { - SubGhzRadioDeviceTypeInternal, - SubGhzRadioDeviceTypeExternalCC1101, -} SubGhzRadioDeviceType; - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type); - -void radio_device_loader_end(const SubGhzDevice* radio_device); \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_10px.png b/applications/external/spectrum_analyzer/spectrum_10px.png deleted file mode 100644 index 743c2460b..000000000 Binary files a/applications/external/spectrum_analyzer/spectrum_10px.png and /dev/null differ diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer.c b/applications/external/spectrum_analyzer/spectrum_analyzer.c deleted file mode 100644 index 345dd008b..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer.c +++ /dev/null @@ -1,611 +0,0 @@ -#include -#include - -#include -#include -#include -#include "spectrum_analyzer.h" - -#include -#include "spectrum_analyzer_worker.h" - -typedef struct { - uint32_t center_freq; - uint8_t width; - uint8_t modulation; - uint8_t band; - uint8_t vscroll; - - uint32_t channel0_frequency; - uint32_t spacing; - - bool mode_change; - bool modulation_change; - - float max_rssi; - uint8_t max_rssi_dec; - uint8_t max_rssi_channel; - uint8_t channel_ss[NUM_CHANNELS]; -} SpectrumAnalyzerModel; - -typedef struct { - SpectrumAnalyzerModel* model; - FuriMutex* model_mutex; - - FuriMessageQueue* event_queue; - - ViewPort* view_port; - Gui* gui; - - SpectrumAnalyzerWorker* worker; -} SpectrumAnalyzer; - -void spectrum_analyzer_draw_scale(Canvas* canvas, const SpectrumAnalyzerModel* model) { - // Draw line - canvas_draw_line( - canvas, FREQ_START_X, FREQ_BOTTOM_Y, FREQ_START_X + FREQ_LENGTH_X, FREQ_BOTTOM_Y); - // Draw minor scale - for(int i = FREQ_START_X; i < FREQ_START_X + FREQ_LENGTH_X; i += 5) { - canvas_draw_line(canvas, i, FREQ_BOTTOM_Y, i, FREQ_BOTTOM_Y + 2); - } - // Draw major scale - for(int i = FREQ_START_X; i < FREQ_START_X + FREQ_LENGTH_X; i += 25) { - canvas_draw_line(canvas, i, FREQ_BOTTOM_Y, i, FREQ_BOTTOM_Y + 4); - } - - // Draw scale tags - uint32_t tag_left = 0; - uint32_t tag_center = 0; - uint32_t tag_right = 0; - char temp_str[18]; - - tag_center = model->center_freq; - - switch(model->width) { - case NARROW: - tag_left = model->center_freq - 2000; - tag_right = model->center_freq + 2000; - break; - case ULTRANARROW: - tag_left = model->center_freq - 1000; - tag_right = model->center_freq + 1000; - break; - case PRECISE: - tag_left = model->center_freq - 200; - tag_right = model->center_freq + 200; - break; - case ULTRAWIDE: - tag_left = model->center_freq - 40000; - tag_right = model->center_freq + 40000; - break; - default: - tag_left = model->center_freq - 10000; - tag_right = model->center_freq + 10000; - } - - canvas_set_font(canvas, FontSecondary); - switch(model->width) { - case PRECISE: - case ULTRANARROW: - snprintf(temp_str, 18, "%.1f", ((double)tag_left) / 1000); - canvas_draw_str_aligned(canvas, FREQ_START_X, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%.1f", ((double)tag_center) / 1000); - canvas_draw_str_aligned(canvas, 128 / 2, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%.1f", ((double)tag_right) / 1000); - canvas_draw_str_aligned( - canvas, FREQ_START_X + FREQ_LENGTH_X - 1, 63, AlignCenter, AlignBottom, temp_str); - break; - default: - snprintf(temp_str, 18, "%lu", tag_left / 1000); - canvas_draw_str_aligned(canvas, FREQ_START_X, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%lu", tag_center / 1000); - canvas_draw_str_aligned(canvas, 128 / 2, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%lu", tag_right / 1000); - canvas_draw_str_aligned( - canvas, FREQ_START_X + FREQ_LENGTH_X - 1, 63, AlignCenter, AlignBottom, temp_str); - } -} - -static void spectrum_analyzer_render_callback(Canvas* const canvas, void* ctx) { - SpectrumAnalyzer* spectrum_analyzer = ctx; - //furi_check(furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - SpectrumAnalyzerModel* model = spectrum_analyzer->model; - - spectrum_analyzer_draw_scale(canvas, model); - - for(uint8_t column = 0; column < 128; column++) { - uint8_t ss = model->channel_ss[column + 2]; - // Compress height to max of 64 values (255>>2) - uint8_t s = MAX((ss - model->vscroll) >> 2, 0); - uint8_t y = FREQ_BOTTOM_Y - s; // bar height - - // Draw each bar - canvas_draw_line(canvas, column, FREQ_BOTTOM_Y, column, y); - } - - if(model->mode_change) { - char temp_mode_str[12]; - switch(model->width) { - case NARROW: - strncpy(temp_mode_str, "NARROW", 12); - break; - case ULTRANARROW: - strncpy(temp_mode_str, "ULTRANARROW", 12); - break; - case PRECISE: - strncpy(temp_mode_str, "PRECISE", 12); - break; - case ULTRAWIDE: - strncpy(temp_mode_str, "ULTRAWIDE", 12); - break; - default: - strncpy(temp_mode_str, "WIDE", 12); - break; - } - - // Current mode label - char tmp_str[21]; - snprintf(tmp_str, 21, "Mode: %s", temp_mode_str); - canvas_draw_str_aligned(canvas, 127, 4, AlignRight, AlignTop, tmp_str); - } - - if(model->modulation_change) { - char temp_mod_str[12]; - switch(model->modulation) { - case NARROW_MODULATION: - strncpy(temp_mod_str, "NARROW", 12); - break; - default: - strncpy(temp_mod_str, "DEFAULT", 12); - break; - } - - // Current modulation label - char tmp_str[27]; - snprintf(tmp_str, 27, "Modulation: %s", temp_mod_str); - canvas_draw_str_aligned(canvas, 127, 4, AlignRight, AlignTop, tmp_str); - } - - // Draw cross and label - if(model->max_rssi > PEAK_THRESHOLD) { - // Compress height to max of 64 values (255>>2) - uint8_t max_y = MAX((model->max_rssi_dec - model->vscroll) >> 2, 0); - max_y = (FREQ_BOTTOM_Y - max_y); - - // Cross - int16_t x1, x2, y1, y2; - x1 = model->max_rssi_channel - 2 - 2; - if(x1 < 0) x1 = 0; - y1 = max_y - 2; - if(y1 < 0) y1 = 0; - x2 = model->max_rssi_channel - 2 + 2; - if(x2 > 127) x2 = 127; - y2 = max_y + 2; - if(y2 > 63) y2 = 63; // SHOULD NOT HAPPEN CHECK! - canvas_draw_line(canvas, x1, y1, x2, y2); - - x1 = model->max_rssi_channel - 2 + 2; - if(x1 > 127) x1 = 127; - y1 = max_y - 2; - if(y1 < 0) y1 = 0; - x2 = model->max_rssi_channel - 2 - 2; - if(x2 < 0) x2 = 0; - y2 = max_y + 2; - if(y2 > 63) y2 = 63; // SHOULD NOT HAPPEN CHECK! - canvas_draw_line(canvas, (uint8_t)x1, (uint8_t)y1, (uint8_t)x2, (uint8_t)y2); - - // Label - char temp_str[36]; - snprintf( - temp_str, - 36, - "Peak: %3.2f Mhz %3.1f dbm", - ((double)(model->channel0_frequency + (model->max_rssi_channel * model->spacing)) / - 1000000), - (double)model->max_rssi); - canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, temp_str); - } - - //furi_mutex_release(spectrum_analyzer->model_mutex); - - // FURI_LOG_D("Spectrum", "model->vscroll %u", model->vscroll); -} - -static void spectrum_analyzer_input_callback(InputEvent* input_event, void* ctx) { - SpectrumAnalyzer* spectrum_analyzer = ctx; - // Handle short and long presses - if(input_event->type == InputTypeShort || input_event->type == InputTypeLong) { - furi_message_queue_put(spectrum_analyzer->event_queue, input_event, FuriWaitForever); - } -} - -static void spectrum_analyzer_worker_callback( - void* channel_ss, - float max_rssi, - uint8_t max_rssi_dec, - uint8_t max_rssi_channel, - void* context) { - SpectrumAnalyzer* spectrum_analyzer = context; - furi_check( - furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - SpectrumAnalyzerModel* model = (SpectrumAnalyzerModel*)spectrum_analyzer->model; - memcpy(model->channel_ss, (uint8_t*)channel_ss, sizeof(uint8_t) * NUM_CHANNELS); - model->max_rssi = max_rssi; - model->max_rssi_dec = max_rssi_dec; - model->max_rssi_channel = max_rssi_channel; - - furi_mutex_release(spectrum_analyzer->model_mutex); - view_port_update(spectrum_analyzer->view_port); -} - -void spectrum_analyzer_calculate_frequencies(SpectrumAnalyzerModel* model) { - // REDO ALL THIS. CALCULATE ONLY WITH SPACING! - - uint8_t new_band; - uint32_t min_hz; - uint32_t max_hz; - uint32_t margin; - uint32_t step; - uint32_t upper_limit; - uint32_t lower_limit; - uint32_t next_up; - uint32_t next_down; - uint8_t next_band_up; - uint8_t next_band_down; - - switch(model->width) { - case NARROW: - margin = NARROW_MARGIN; - step = NARROW_STEP; - model->spacing = NARROW_SPACING; - break; - case ULTRANARROW: - margin = ULTRANARROW_MARGIN; - step = ULTRANARROW_STEP; - model->spacing = ULTRANARROW_SPACING; - break; - case PRECISE: - margin = PRECISE_MARGIN; - step = PRECISE_STEP; - model->spacing = PRECISE_SPACING; - break; - case ULTRAWIDE: - margin = ULTRAWIDE_MARGIN; - step = ULTRAWIDE_STEP; - model->spacing = ULTRAWIDE_SPACING; - /* nearest 20 MHz step */ - model->center_freq = ((model->center_freq + 10000) / 20000) * 20000; - break; - default: - margin = WIDE_MARGIN; - step = WIDE_STEP; - model->spacing = WIDE_SPACING; - /* nearest 5 MHz step */ - model->center_freq = ((model->center_freq + 2000) / 5000) * 5000; - break; - } - - /* handle cases near edges of bands */ - if(model->center_freq > EDGE_900) { - new_band = BAND_900; - upper_limit = UPPER(MAX_900, margin, step); - lower_limit = LOWER(MIN_900, margin, step); - next_up = LOWER(MIN_300, margin, step); - next_down = UPPER(MAX_400, margin, step); - next_band_up = BAND_300; - next_band_down = BAND_400; - } else if(model->center_freq > EDGE_400) { - new_band = BAND_400; - upper_limit = UPPER(MAX_400, margin, step); - lower_limit = LOWER(MIN_400, margin, step); - next_up = LOWER(MIN_900, margin, step); - next_down = UPPER(MAX_300, margin, step); - next_band_up = BAND_900; - next_band_down = BAND_300; - } else { - new_band = BAND_300; - upper_limit = UPPER(MAX_300, margin, step); - lower_limit = LOWER(MIN_300, margin, step); - next_up = LOWER(MIN_400, margin, step); - next_down = UPPER(MAX_900, margin, step); - next_band_up = BAND_400; - next_band_down = BAND_900; - } - - if(model->center_freq > upper_limit) { - model->center_freq = upper_limit; - if(new_band == model->band) { - new_band = next_band_up; - model->center_freq = next_up; - } - } else if(model->center_freq < lower_limit) { - model->center_freq = lower_limit; - if(new_band == model->band) { - new_band = next_band_down; - model->center_freq = next_down; - } - } - - model->band = new_band; - /* doing everything in Hz from here on */ - switch(model->band) { - case BAND_400: - min_hz = MIN_400 * 1000; - max_hz = MAX_400 * 1000; - break; - case BAND_300: - min_hz = MIN_300 * 1000; - max_hz = MAX_300 * 1000; - break; - default: - min_hz = MIN_900 * 1000; - max_hz = MAX_900 * 1000; - break; - } - - model->channel0_frequency = - model->center_freq * 1000 - (model->spacing * ((NUM_CHANNELS / 2) + 1)); - - // /* calibrate upper channels */ - // hz = model->center_freq * 1000000; - // max_chan = NUM_CHANNELS / 2; - // while (hz <= max_hz && max_chan < NUM_CHANNELS) { - // instance->chan_table[max_chan].frequency = hz; - // FURI_LOG_T("Spectrum", "calibrate_freq ch[%u]: %lu", max_chan, hz); - // hz += model->spacing; - // max_chan++; - // } - - // /* calibrate lower channels */ - // hz = instance->freq * 1000000 - model->spacing; - // min_chan = NUM_CHANNELS / 2; - // while (hz >= min_hz && min_chan > 0) { - // min_chan--; - // instance->chan_table[min_chan].frequency = hz; - // FURI_LOG_T("Spectrum", "calibrate_freq ch[%u]: %lu", min_chan, hz); - // hz -= model->spacing; - // } - - model->max_rssi = -200.0; - model->max_rssi_dec = 0; - - FURI_LOG_D("Spectrum", "setup_frequencies - max_hz: %lu - min_hz: %lu", max_hz, min_hz); - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - FURI_LOG_D( - "Spectrum", - "ch[0]: %lu - ch[%u]: %lu", - model->channel0_frequency, - NUM_CHANNELS - 1, - model->channel0_frequency + ((NUM_CHANNELS - 1) * model->spacing)); -} - -SpectrumAnalyzer* spectrum_analyzer_alloc() { - SpectrumAnalyzer* instance = malloc(sizeof(SpectrumAnalyzer)); - instance->model = malloc(sizeof(SpectrumAnalyzerModel)); - - SpectrumAnalyzerModel* model = instance->model; - - for(uint8_t ch = 0; ch < NUM_CHANNELS - 1; ch++) { - model->channel_ss[ch] = 0; - } - model->max_rssi_dec = 0; - model->max_rssi_channel = 0; - model->max_rssi = PEAK_THRESHOLD - 1; // Should initializar to < PEAK_THRESHOLD - - model->center_freq = DEFAULT_FREQ; - model->width = WIDE; - model->modulation = DEFAULT_MODULATION; - model->band = BAND_400; - - model->vscroll = DEFAULT_VSCROLL; - - instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - instance->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - instance->worker = spectrum_analyzer_worker_alloc(); - - spectrum_analyzer_worker_set_callback( - instance->worker, spectrum_analyzer_worker_callback, instance); - - // Set system callbacks - instance->view_port = view_port_alloc(); - view_port_draw_callback_set(instance->view_port, spectrum_analyzer_render_callback, instance); - view_port_input_callback_set(instance->view_port, spectrum_analyzer_input_callback, instance); - - // Open GUI and register view_port - instance->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); - - return instance; -} - -void spectrum_analyzer_free(SpectrumAnalyzer* instance) { - // view_port_enabled_set(view_port, false); - gui_remove_view_port(instance->gui, instance->view_port); - furi_record_close(RECORD_GUI); - view_port_free(instance->view_port); - - spectrum_analyzer_worker_free(instance->worker); - - furi_message_queue_free(instance->event_queue); - - furi_mutex_free(instance->model_mutex); - - free(instance->model); - free(instance); -} - -int32_t spectrum_analyzer_app(void* p) { - UNUSED(p); - - SpectrumAnalyzer* spectrum_analyzer = spectrum_analyzer_alloc(); - InputEvent input; - - furi_hal_power_suppress_charge_enter(); - - FURI_LOG_D("Spectrum", "Main Loop - Starting worker"); - furi_delay_ms(50); - - spectrum_analyzer_worker_start(spectrum_analyzer->worker); - spectrum_analyzer_calculate_frequencies(spectrum_analyzer->model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - spectrum_analyzer->model->channel0_frequency, - spectrum_analyzer->model->spacing, - spectrum_analyzer->model->width); - - FURI_LOG_D("Spectrum", "Main Loop - Wait on queue"); - furi_delay_ms(50); - - while(furi_message_queue_get(spectrum_analyzer->event_queue, &input, FuriWaitForever) == - FuriStatusOk) { - furi_check( - furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - FURI_LOG_D("Spectrum", "Main Loop - Input: %u", input.key); - - SpectrumAnalyzerModel* model = spectrum_analyzer->model; - - uint8_t vstep = VERTICAL_SHORT_STEP; - uint32_t hstep; - - bool exit_loop = false; - - switch(model->width) { - case NARROW: - hstep = NARROW_STEP; - break; - case ULTRANARROW: - hstep = ULTRANARROW_STEP; - break; - case ULTRAWIDE: - hstep = ULTRAWIDE_STEP; - break; - case PRECISE: - hstep = PRECISE_STEP; - break; - default: - hstep = WIDE_STEP; - break; - } - - switch(input.type) { - case InputTypeShort: - switch(input.key) { - case InputKeyUp: - model->vscroll = MAX(model->vscroll - vstep, MIN_VSCROLL); - FURI_LOG_D("Spectrum", "Vscroll: %u", model->vscroll); - break; - case InputKeyDown: - model->vscroll = MIN(model->vscroll + vstep, MAX_VSCROLL); - FURI_LOG_D("Spectrum", "Vscroll: %u", model->vscroll); - break; - case InputKeyRight: - model->center_freq += hstep; - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - break; - case InputKeyLeft: - model->center_freq -= hstep; - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - break; - case InputKeyOk: { - switch(model->width) { - case WIDE: - model->width = NARROW; - break; - case NARROW: - model->width = ULTRANARROW; - break; - case ULTRANARROW: - model->width = PRECISE; - break; - case PRECISE: - model->width = ULTRAWIDE; - break; - case ULTRAWIDE: - model->width = WIDE; - break; - default: - model->width = WIDE; - break; - } - } - model->mode_change = true; - view_port_update(spectrum_analyzer->view_port); - - furi_delay_ms(1000); - - model->mode_change = false; - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - FURI_LOG_D("Spectrum", "Width: %u", model->width); - break; - case InputKeyBack: - exit_loop = true; - break; - default: - break; - } - break; - case InputTypeLong: - switch(input.key) { - case InputKeyOk: - FURI_LOG_D("Spectrum", "InputTypeLong"); - switch(model->modulation) { - case NARROW_MODULATION: - model->modulation = DEFAULT_MODULATION; - break; - case DEFAULT_MODULATION: - default: - model->modulation = NARROW_MODULATION; - break; - } - - model->modulation_change = true; - view_port_update(spectrum_analyzer->view_port); - - furi_delay_ms(1000); - - model->modulation_change = false; - spectrum_analyzer_worker_set_modulation( - spectrum_analyzer->worker, spectrum_analyzer->model->modulation); - break; - default: - break; - } - break; - default: - break; - } - - furi_mutex_release(spectrum_analyzer->model_mutex); - view_port_update(spectrum_analyzer->view_port); - if(exit_loop == true) break; - } - - spectrum_analyzer_worker_stop(spectrum_analyzer->worker); - - furi_hal_power_suppress_charge_exit(); - - spectrum_analyzer_free(spectrum_analyzer); - - return 0; -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer.h b/applications/external/spectrum_analyzer/spectrum_analyzer.h deleted file mode 100644 index bdd4c841c..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer.h +++ /dev/null @@ -1,84 +0,0 @@ -#define NUM_CHANNELS 132 -#define NUM_CHUNKS 6 -#define CHUNK_SIZE (NUM_CHANNELS / NUM_CHUNKS) - -// Screen coordinates -#define FREQ_BOTTOM_Y 50 -#define FREQ_START_X 14 -// How many channels displayed on the scale (On screen still 218) -#define FREQ_LENGTH_X 102 -// dBm threshold to show peak value -#define PEAK_THRESHOLD -85 - -/* - * ultrawide mode: 80 MHz on screen, 784 kHz per channel - * wide mode (default): 20 MHz on screen, 196 kHz per channel - * narrow mode: 4 MHz on screen, 39 kHz per channel - * ultranarrow mode: 2 MHz on screen, 19 kHz per channel - * precise mode: 400 KHz on screen, 3.92 kHz per channel - */ -#define WIDE 0 -#define NARROW 1 -#define ULTRAWIDE 2 -#define ULTRANARROW 3 -#define PRECISE 4 - -/* channel spacing in Hz */ -#define WIDE_SPACING 196078 -#define NARROW_SPACING 39215 -#define ULTRAWIDE_SPACING 784313 -#define ULTRANARROW_SPACING 19607 -#define PRECISE_SPACING 3921 - -/* vertical scrolling */ -#define VERTICAL_SHORT_STEP 16 -#define MAX_VSCROLL 120 -#define MIN_VSCROLL 0 -#define DEFAULT_VSCROLL 48 - -/* frequencies in KHz */ -#define DEFAULT_FREQ 440000 -#define WIDE_STEP 5000 -#define NARROW_STEP 1000 -#define ULTRAWIDE_STEP 20000 -#define ULTRANARROW_STEP 500 -#define PRECISE_STEP 100 - -/* margin in KHz */ -#define WIDE_MARGIN 13000 -#define NARROW_MARGIN 3000 -#define ULTRAWIDE_MARGIN 42000 -#define ULTRANARROW_MARGIN 1000 -#define PRECISE_MARGIN 200 - -/* frequency bands supported by device */ -#define BAND_300 0 -#define BAND_400 1 -#define BAND_900 2 - -/* band limits in KHz */ -#define MIN_300 281000 -#define CEN_300 315000 -#define MAX_300 361000 -#define MIN_400 378000 -#define CEN_400 435000 -#define MAX_400 481000 -#define MIN_900 749000 -#define CEN_900 855000 -#define MAX_900 962000 - -/* band transition points in KHz */ -#define EDGE_400 369000 -#define EDGE_900 615000 - -/* VCO transition points in Hz */ -#define MID_300 318000000 -#define MID_400 424000000 -#define MID_900 848000000 - -#define UPPER(a, b, c) ((((a) - (b) + ((c) / 2)) / (c)) * (c)) -#define LOWER(a, b, c) ((((a) + (b)) / (c)) * (c)) - -/* Modulation references */ -#define DEFAULT_MODULATION 0 -#define NARROW_MODULATION 1 \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c b/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c deleted file mode 100644 index 4076e8a04..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c +++ /dev/null @@ -1,345 +0,0 @@ -#include "spectrum_analyzer.h" -#include "spectrum_analyzer_worker.h" - -#include -#include - -#include "helpers/radio_device_loader.h" - -#include - -struct SpectrumAnalyzerWorker { - FuriThread* thread; - bool should_work; - - SpectrumAnalyzerWorkerCallback callback; - void* callback_context; - - const SubGhzDevice* radio_device; - - uint32_t channel0_frequency; - uint32_t spacing; - uint8_t width; - uint8_t modulation; - float max_rssi; - uint8_t max_rssi_dec; - uint8_t max_rssi_channel; - - uint8_t channel_ss[NUM_CHANNELS]; -}; - -/* set the channel bandwidth */ -void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance) { - uint8_t filter_config[2][2] = { - {CC1101_MDMCFG4, 0}, - {0, 0}, - }; - - // FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_set_filter: width = %u", instance->width); - - /* channel spacing should fit within 80% of channel filter bandwidth */ - switch(instance->width) { - case NARROW: - filter_config[0][1] = 0xFC; /* 39.2 kHz / .8 = 49 kHz --> 58 kHz */ - break; - case ULTRAWIDE: - filter_config[0][1] = 0x0C; /* 784 kHz / .8 = 980 kHz --> 812 kHz */ - break; - default: - filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */ - break; - } - - UNUSED(filter_config); - // furi_hal_subghz_load_registers((uint8_t*)filter_config); -} - -static int32_t spectrum_analyzer_worker_thread(void* context) { - furi_assert(context); - SpectrumAnalyzerWorker* instance = context; - - FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_thread: Start"); - - // Start CC1101 - subghz_devices_reset(instance->radio_device); - subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetOok650Async, NULL); - subghz_devices_set_frequency(instance->radio_device, 433920000); - subghz_devices_flush_rx(instance->radio_device); - subghz_devices_set_rx(instance->radio_device); - - // Default modulation - const uint8_t default_modulation[] = { - - /* Frequency Synthesizer Control */ - CC1101_FSCTRL0, - 0x00, - CC1101_FSCTRL1, - 0x12, // IF = (26*10^6) / (2^10) * 0x12 = 304687.5 Hz - - // Modem Configuration - // CC1101_MDMCFG0, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG1, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG2, - // 0x30, // Format ASK/OOK, No preamble/sync - // CC1101_MDMCFG3, - // 0x32, // Data rate is 121.399 kBaud - CC1101_MDMCFG4, - 0x6C, // Rx BW filter is 270.83 kHz - - /* Frequency Offset Compensation Configuration */ - // CC1101_FOCCFG, - // 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - // CC1101_AGCCTRL0, - // 0x91, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - // CC1101_AGCCTRL1, - // 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - CC1101_AGCCTRL2, - 0xC0, // 03 - The 3 highest DVGA gain settings can not be used; 000 - MAX LNA+LNA2; 000 - MAIN_TARGET 24 dB - - /* Frontend configuration */ - // CC1101_FREND0, - // 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] - // CC1101_FREND1, - // 0xB6, // - - CC1101_TEST2, - 0x88, - CC1101_TEST1, - 0x31, - CC1101_TEST0, - 0x09, - - /* End */ - 0, - 0, - - // ook_async_patable - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - - // Narrow modulation - const uint8_t narrow_modulation[] = { - - /* Frequency Synthesizer Control */ - CC1101_FSCTRL0, - 0x00, - CC1101_FSCTRL1, - 0x00, // IF = (26*10^6) / (2^10) * 0x00 = 0 Hz - - // Modem Configuration - // CC1101_MDMCFG0, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG1, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG2, - // 0x30, // Format ASK/OOK, No preamble/sync - // CC1101_MDMCFG3, - // 0x32, // Data rate is 121.399 kBaud - CC1101_MDMCFG4, - 0xFC, // Rx BW filter is 58.04 kHz - - /* Frequency Offset Compensation Configuration */ - // CC1101_FOCCFG, - // 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - CC1101_AGCCTRL0, - 0x30, // 00 - NO hysteresis, symmetric dead zone, high gain ; 11 - 32 samples agc; 00 - Normal AGC, 00 - 8dB boundary - CC1101_AGCCTRL1, - 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - CC1101_AGCCTRL2, - 0x84, // 02 - The 2 highest DVGA gain settings can not be used; 000 - MAX LNA+LNA2; 100 - MAIN_TARGET 36 dB - - /* Frontend configuration */ - // CC1101_FREND0, - // 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] - // CC1101_FREND1, - // 0xB6, // - - CC1101_TEST2, - 0x88, - CC1101_TEST1, - 0x31, - CC1101_TEST0, - 0x09, - - /* End */ - 0, - 0, - - // ook_async_patable - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - - const uint8_t* modulations[] = {default_modulation, narrow_modulation}; - - while(instance->should_work) { - furi_delay_ms(50); - - // FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop"); - subghz_devices_idle(instance->radio_device); - subghz_devices_load_preset( - instance->radio_device, - FuriHalSubGhzPresetCustom, - (uint8_t*)modulations[instance->modulation]); - //subghz_devices_load_preset( - // instance->radio_device, FuriHalSubGhzPresetCustom, (uint8_t*)default_modulation); - //furi_hal_subghz_load_custom_preset(modulations[instance->modulation]); - - // TODO: Check filter! - // spectrum_analyzer_worker_set_filter(instance); - - instance->max_rssi_dec = 0; - - // Visit each channel non-consecutively - for(uint8_t ch_offset = 0, chunk = 0; ch_offset < CHUNK_SIZE; - ++chunk >= NUM_CHUNKS && ++ch_offset && (chunk = 0)) { - uint8_t ch = chunk * CHUNK_SIZE + ch_offset; - - if(subghz_devices_is_frequency_valid( - instance->radio_device, - instance->channel0_frequency + (ch * instance->spacing))) - subghz_devices_set_frequency( - instance->radio_device, - instance->channel0_frequency + (ch * instance->spacing)); - - subghz_devices_set_rx(instance->radio_device); - furi_delay_ms(3); - - // dec dBm - //max_ss = 127 -> -10.5 - //max_ss = 0 -> -74.0 - //max_ss = 255 -> -74.5 - //max_ss = 128 -> -138.0 - instance->channel_ss[ch] = (subghz_devices_get_rssi(instance->radio_device) + 138) * 2; - - if(instance->channel_ss[ch] > instance->max_rssi_dec) { - instance->max_rssi_dec = instance->channel_ss[ch]; - instance->max_rssi = (instance->channel_ss[ch] / 2) - 138; - instance->max_rssi_channel = ch; - } - - subghz_devices_idle(instance->radio_device); - } - - // FURI_LOG_T("SpectrumWorker", "channel_ss[0]: %u", instance->channel_ss[0]); - - // Report results back to main thread - if(instance->callback) { - instance->callback( - (void*)&(instance->channel_ss), - instance->max_rssi, - instance->max_rssi_dec, - instance->max_rssi_channel, - instance->callback_context); - } - } - - return 0; -} - -SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc() { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: Start"); - - SpectrumAnalyzerWorker* instance = malloc(sizeof(SpectrumAnalyzerWorker)); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SpectrumWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, spectrum_analyzer_worker_thread); - - subghz_devices_init(); - - instance->radio_device = - radio_device_loader_set(instance->radio_device, SubGhzRadioDeviceTypeExternalCC1101); - - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: End"); - - return instance; -} - -void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_free"); - furi_assert(instance); - furi_thread_free(instance->thread); - - subghz_devices_sleep(instance->radio_device); - radio_device_loader_end(instance->radio_device); - - subghz_devices_deinit(); - - free(instance); -} - -void spectrum_analyzer_worker_set_callback( - SpectrumAnalyzerWorker* instance, - SpectrumAnalyzerWorkerCallback callback, - void* context) { - furi_assert(instance); - instance->callback = callback; - instance->callback_context = context; -} - -void spectrum_analyzer_worker_set_frequencies( - SpectrumAnalyzerWorker* instance, - uint32_t channel0_frequency, - uint32_t spacing, - uint8_t width) { - furi_assert(instance); - - FURI_LOG_D( - "SpectrumWorker", - "spectrum_analyzer_worker_set_frequencies - channel0_frequency= %lu - spacing = %lu - width = %u", - channel0_frequency, - spacing, - width); - - instance->channel0_frequency = channel0_frequency; - instance->spacing = spacing; - instance->width = width; -} - -void spectrum_analyzer_worker_set_modulation(SpectrumAnalyzerWorker* instance, uint8_t modulation) { - furi_assert(instance); - - FURI_LOG_D( - "SpectrumWorker", "spectrum_analyzer_worker_set_modulation - modulation = %u", modulation); - - instance->modulation = modulation; -} - -void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_start"); - - furi_assert(instance); - furi_assert(instance->should_work == false); - - instance->should_work = true; - furi_thread_start(instance->thread); -} - -void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_stop"); - furi_assert(instance); - furi_assert(instance->should_work == true); - - instance->should_work = false; - furi_thread_join(instance->thread); -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h b/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h deleted file mode 100644 index 796f532e6..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -typedef void (*SpectrumAnalyzerWorkerCallback)( - void* chan_table, - float max_rssi, - uint8_t max_rssi_dec, - uint8_t max_rssi_channel, - void* context); - -typedef struct SpectrumAnalyzerWorker SpectrumAnalyzerWorker; - -SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc(); - -void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_set_callback( - SpectrumAnalyzerWorker* instance, - SpectrumAnalyzerWorkerCallback callback, - void* context); - -void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_set_frequencies( - SpectrumAnalyzerWorker* instance, - uint32_t channel0_frequency, - uint32_t spacing, - uint8_t width); - -void spectrum_analyzer_worker_set_modulation(SpectrumAnalyzerWorker* instance, uint8_t modulation); - -void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance); diff --git a/applications/external/tanksgame/application.fam b/applications/external/tanksgame/application.fam deleted file mode 100644 index bf6bd1b4a..000000000 --- a/applications/external/tanksgame/application.fam +++ /dev/null @@ -1,12 +0,0 @@ -App( - appid="tanks", - name="Tanks", - apptype=FlipperAppType.EXTERNAL, - entry_point="tanks_game_app", - cdefines=["APP_TANKS_GAME"], - requires=["gui", "subghz"], - stack_size=4 * 1024, - fap_icon="tanksIcon.png", - fap_category="Games", - fap_icon_assets="images", -) diff --git a/applications/external/tanksgame/constants.h b/applications/external/tanksgame/constants.h deleted file mode 100644 index d65dd32ea..000000000 --- a/applications/external/tanksgame/constants.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FLIPPERZERO_FIRMWARE_CONSTANTS_H -#define FLIPPERZERO_FIRMWARE_CONSTANTS_H - -const uint8_t SCREEN_WIDTH_TANKS = 128; -const uint8_t SCREEN_HEIGHT_TANKS = 64; - -const uint8_t FIELD_WIDTH = 16; -const uint8_t FIELD_HEIGHT = 11; - -const uint16_t TURN_LENGTH = 300; -const uint16_t LONG_PRESS_LENGTH = 10; - -const uint8_t SHOT_COOLDOWN = 5; -const uint8_t RESPAWN_COOLDOWN = 8; -const uint8_t PLAYER_RESPAWN_COOLDOWN = 1; - -const uint8_t CELL_LENGTH_PIXELS = 6; - -#endif diff --git a/applications/external/tanksgame/helpers/radio_device_loader.c b/applications/external/tanksgame/helpers/radio_device_loader.c deleted file mode 100644 index d2cffde58..000000000 --- a/applications/external/tanksgame/helpers/radio_device_loader.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "radio_device_loader.h" - -#include -#include - -static void radio_device_loader_power_on() { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); - } -} - -static void radio_device_loader_power_off() { - if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); -} - -bool radio_device_loader_is_connect_external(const char* name) { - bool is_connect = false; - bool is_otg_enabled = furi_hal_power_is_otg_enabled(); - - if(!is_otg_enabled) { - radio_device_loader_power_on(); - } - - const SubGhzDevice* device = subghz_devices_get_by_name(name); - if(device) { - is_connect = subghz_devices_is_connect(device); - } - - if(!is_otg_enabled) { - radio_device_loader_power_off(); - } - return is_connect; -} - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type) { - const SubGhzDevice* radio_device; - - if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && - radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) { - radio_device_loader_power_on(); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); - subghz_devices_begin(radio_device); - } else if(current_radio_device == NULL) { - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } else { - radio_device_loader_end(current_radio_device); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } - - return radio_device; -} - -void radio_device_loader_end(const SubGhzDevice* radio_device) { - furi_assert(radio_device); - radio_device_loader_power_off(); - if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) { - subghz_devices_end(radio_device); - } -} \ No newline at end of file diff --git a/applications/external/tanksgame/helpers/radio_device_loader.h b/applications/external/tanksgame/helpers/radio_device_loader.h deleted file mode 100644 index bee4e2c36..000000000 --- a/applications/external/tanksgame/helpers/radio_device_loader.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -/** SubGhzRadioDeviceType */ -typedef enum { - SubGhzRadioDeviceTypeInternal, - SubGhzRadioDeviceTypeExternalCC1101, -} SubGhzRadioDeviceType; - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type); - -void radio_device_loader_end(const SubGhzDevice* radio_device); \ No newline at end of file diff --git a/applications/external/tanksgame/images/HappyFlipper_128x64.png b/applications/external/tanksgame/images/HappyFlipper_128x64.png deleted file mode 100644 index d95412f3f..000000000 Binary files a/applications/external/tanksgame/images/HappyFlipper_128x64.png and /dev/null differ diff --git a/applications/external/tanksgame/images/TanksSplashScreen_128x64.png b/applications/external/tanksgame/images/TanksSplashScreen_128x64.png deleted file mode 100644 index a0dc26487..000000000 Binary files a/applications/external/tanksgame/images/TanksSplashScreen_128x64.png and /dev/null differ diff --git a/applications/external/tanksgame/images/enemy_down.png b/applications/external/tanksgame/images/enemy_down.png deleted file mode 100644 index 84d64ed44..000000000 Binary files a/applications/external/tanksgame/images/enemy_down.png and /dev/null differ diff --git a/applications/external/tanksgame/images/enemy_left.png b/applications/external/tanksgame/images/enemy_left.png deleted file mode 100644 index e118d03a8..000000000 Binary files a/applications/external/tanksgame/images/enemy_left.png and /dev/null differ diff --git a/applications/external/tanksgame/images/enemy_right.png b/applications/external/tanksgame/images/enemy_right.png deleted file mode 100644 index 8c5f0603b..000000000 Binary files a/applications/external/tanksgame/images/enemy_right.png and /dev/null differ diff --git a/applications/external/tanksgame/images/enemy_up.png b/applications/external/tanksgame/images/enemy_up.png deleted file mode 100644 index 8ad01f635..000000000 Binary files a/applications/external/tanksgame/images/enemy_up.png and /dev/null differ diff --git a/applications/external/tanksgame/images/projectile_down.png b/applications/external/tanksgame/images/projectile_down.png deleted file mode 100644 index fd3f8c123..000000000 Binary files a/applications/external/tanksgame/images/projectile_down.png and /dev/null differ diff --git a/applications/external/tanksgame/images/projectile_left.png b/applications/external/tanksgame/images/projectile_left.png deleted file mode 100644 index c8c54786d..000000000 Binary files a/applications/external/tanksgame/images/projectile_left.png and /dev/null differ diff --git a/applications/external/tanksgame/images/projectile_right.png b/applications/external/tanksgame/images/projectile_right.png deleted file mode 100644 index fbf5359ad..000000000 Binary files a/applications/external/tanksgame/images/projectile_right.png and /dev/null differ diff --git a/applications/external/tanksgame/images/projectile_up.png b/applications/external/tanksgame/images/projectile_up.png deleted file mode 100644 index 532446657..000000000 Binary files a/applications/external/tanksgame/images/projectile_up.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_base.png b/applications/external/tanksgame/images/tank_base.png deleted file mode 100644 index 11a524ffa..000000000 Binary files a/applications/external/tanksgame/images/tank_base.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_down.png b/applications/external/tanksgame/images/tank_down.png deleted file mode 100644 index d4e2c8786..000000000 Binary files a/applications/external/tanksgame/images/tank_down.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_explosion.png b/applications/external/tanksgame/images/tank_explosion.png deleted file mode 100644 index 8aab727cd..000000000 Binary files a/applications/external/tanksgame/images/tank_explosion.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_hedgehog.png b/applications/external/tanksgame/images/tank_hedgehog.png deleted file mode 100644 index fdd804be9..000000000 Binary files a/applications/external/tanksgame/images/tank_hedgehog.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_left.png b/applications/external/tanksgame/images/tank_left.png deleted file mode 100644 index 2c7fd40e0..000000000 Binary files a/applications/external/tanksgame/images/tank_left.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_right.png b/applications/external/tanksgame/images/tank_right.png deleted file mode 100644 index 436d90a61..000000000 Binary files a/applications/external/tanksgame/images/tank_right.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_stone.png b/applications/external/tanksgame/images/tank_stone.png deleted file mode 100644 index 87f89c8da..000000000 Binary files a/applications/external/tanksgame/images/tank_stone.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_up.png b/applications/external/tanksgame/images/tank_up.png deleted file mode 100644 index 3d4e47579..000000000 Binary files a/applications/external/tanksgame/images/tank_up.png and /dev/null differ diff --git a/applications/external/tanksgame/images/tank_wall.png b/applications/external/tanksgame/images/tank_wall.png deleted file mode 100644 index 88d537cdb..000000000 Binary files a/applications/external/tanksgame/images/tank_wall.png and /dev/null differ diff --git a/applications/external/tanksgame/tanksIcon.png b/applications/external/tanksgame/tanksIcon.png deleted file mode 100644 index 7a2113c0b..000000000 Binary files a/applications/external/tanksgame/tanksIcon.png and /dev/null differ diff --git a/applications/external/tanksgame/tanks_game.c b/applications/external/tanksgame/tanks_game.c deleted file mode 100644 index f9befdc71..000000000 --- a/applications/external/tanksgame/tanks_game.c +++ /dev/null @@ -1,1476 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tanks_icons.h" -#include -#include "helpers/radio_device_loader.h" - -#include "constants.h" - -typedef struct { - // +-----x - // | - // | - // y - uint8_t x; - uint8_t y; -} Point; - -typedef enum { - CellEmpty = 1, - CellWall, - CellExplosion, - CellTankUp, - CellTankRight, - CellTankDown, - CellTankLeft, - CellEnemyUp, - CellEnemyRight, - CellEnemyDown, - CellEnemyLeft, - CellProjectileUp, - CellProjectileRight, - CellProjectileDown, - CellProjectileLeft, -} GameCellState; - -typedef enum { - MenuStateSingleMode, - MenuStateCooperativeServerMode, - MenuStateCooperativeClientMode, -} MenuState; - -typedef enum { - GameStateMenu, - GameStateSingle, - GameStateCooperativeServer, - GameStateCooperativeClient, - GameStateGameOver, -} GameState; - -typedef enum { - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -typedef enum { - ModeSingle, - ModeCooperative, -} Mode; - -typedef struct { - Point coordinates; - Direction direction; - bool explosion; - bool is_p1; - bool is_p2; -} ProjectileState; - -typedef struct { - Point coordinates; - uint16_t score; - uint8_t lives; - Direction direction; - bool moving; - bool shooting; - bool live; - uint8_t cooldown; - uint8_t respawn_cooldown; -} PlayerState; - -typedef struct { - // char map[FIELD_WIDTH][FIELD_HEIGHT]; - char thisMap[16][11]; - Point team_one_respawn_points[3]; - Point team_two_respawn_points[3]; - Mode mode; - bool server; - GameState state; - MenuState menu_state; - ProjectileState* projectiles[100]; - PlayerState* bots[6]; - uint8_t enemies_left; - uint8_t enemies_live; - uint8_t enemies_respawn_cooldown; - uint8_t received; - uint8_t sent; - PlayerState* p1; - PlayerState* p2; - FuriMutex* mutex; -} TanksState; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} TanksEvent; - -typedef enum { - GoesUp, - GoesRight, - GoesDown, - GoesLeft, - Shoots, -} ClientAction; - -//char map[FIELD_HEIGHT][FIELD_WIDTH + 1] = { -char thisMap[11][16 + 1] = { - "* - * -", - " - - = ", - " - - 2", - "1 = - -- ", - "-- = - -- ", - "a-1 = - = 2", - "-- = - -- ", - "1 = - -- ", - " - - 2", - " - - = ", - "* - * -", -}; - -static void tanks_game_write_cell(unsigned char* data, int8_t x, int8_t y, GameCellState cell) { - uint8_t index = y * 16 + x; - data[index] = cell; - // if (x % 2) { - // data[index] = (data[index] & 0b00001111) + (cell << 4); - // } else { - // data[index] = (data[index] & 0b0000) + cell; - // } -} - -// Enum with < 16 items => 4 bits in cell, 2 cells in byte -unsigned char* tanks_game_serialize(const TanksState* const tanks_state) { - static unsigned char result[11 * 16 + 1]; - - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - result[(y * FIELD_WIDTH + x)] = 0; - - GameCellState cell = CellEmpty; - - if(tanks_state->thisMap[x][y] == '-') { - cell = CellWall; - - tanks_game_write_cell(result, x, y, cell); - } - } - } - - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - GameCellState cell = CellEmpty; - - switch(tanks_state->bots[i]->direction) { - case DirectionUp: - cell = CellEnemyUp; - break; - case DirectionDown: - cell = CellEnemyDown; - break; - case DirectionRight: - cell = CellEnemyRight; - break; - case DirectionLeft: - cell = CellEnemyLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, - tanks_state->bots[i]->coordinates.x, - tanks_state->bots[i]->coordinates.y, - cell); - } - } - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - GameCellState cell = CellEmpty; - - switch(tanks_state->projectiles[x]->direction) { - case DirectionUp: - cell = CellProjectileUp; - break; - case DirectionDown: - cell = CellProjectileDown; - break; - case DirectionRight: - cell = CellProjectileRight; - break; - case DirectionLeft: - cell = CellProjectileLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, - tanks_state->projectiles[x]->coordinates.x, - tanks_state->projectiles[x]->coordinates.y, - cell); - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live) { - GameCellState cell = CellEmpty; - - switch(tanks_state->p1->direction) { - case DirectionUp: - cell = CellTankUp; - break; - case DirectionDown: - cell = CellTankDown; - break; - case DirectionRight: - cell = CellTankRight; - break; - case DirectionLeft: - cell = CellTankLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, tanks_state->p1->coordinates.x, tanks_state->p1->coordinates.y, cell); - } - - if(tanks_state->p2 != NULL && tanks_state->p2->live) { - GameCellState cell = CellEmpty; - - switch(tanks_state->p2->direction) { - case DirectionUp: - cell = CellTankUp; - break; - case DirectionDown: - cell = CellTankDown; - break; - case DirectionRight: - cell = CellTankRight; - break; - case DirectionLeft: - cell = CellTankLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, tanks_state->p2->coordinates.x, tanks_state->p2->coordinates.y, cell); - } - - return result; -} - -static void - tanks_game_render_cell(GameCellState cell, uint8_t x, uint8_t y, Canvas* const canvas) { - const Icon* icon; - - if(cell == CellEmpty) { - return; - } - - switch(cell) { - case CellWall: - icon = &I_tank_wall; - break; - case CellExplosion: - icon = &I_tank_explosion; - break; - case CellTankUp: - icon = &I_tank_up; - break; - case CellTankRight: - icon = &I_tank_right; - break; - case CellTankDown: - icon = &I_tank_down; - break; - case CellTankLeft: - icon = &I_tank_left; - break; - case CellEnemyUp: - icon = &I_enemy_up; - break; - case CellEnemyRight: - icon = &I_enemy_right; - break; - case CellEnemyDown: - icon = &I_enemy_down; - break; - case CellEnemyLeft: - icon = &I_enemy_left; - break; - case CellProjectileUp: - icon = &I_projectile_up; - break; - case CellProjectileRight: - icon = &I_projectile_right; - break; - case CellProjectileDown: - icon = &I_projectile_down; - break; - case CellProjectileLeft: - icon = &I_projectile_left; - break; - default: - return; - break; - } - - canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, icon); -} - -static void tanks_game_render_constant_cells(Canvas* const canvas) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - char cell = thisMap[y][x]; - - if(cell == '=') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_stone); - continue; - } - - if(cell == '*') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_hedgehog); - continue; - } - - if(cell == 'a') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_base); - continue; - } - } - } -} - -void tanks_game_deserialize_and_write_to_state(unsigned char* data, TanksState* const tanks_state) { - for(uint8_t i = 0; i < 11 * 16; i++) { - uint8_t x = i % 16; - uint8_t y = i / 16; - tanks_state->thisMap[x][y] = data[i]; - } -} - -void tanks_game_deserialize_and_render(unsigned char* data, Canvas* const canvas) { - //for (uint8_t i = 0; i < 11 * 16 / 2; i++) { - for(uint8_t i = 0; i < 11 * 16; i++) { - char cell = data[i]; - uint8_t x = i % 16; // One line (16 cells) = 8 bytes - uint8_t y = i / 16; - - // GameCellState first = cell >> 4; - // GameCellState second = cell & 0b00001111; - - tanks_game_render_cell(cell, x, y, canvas); - // tanks_game_render_cell(second, x + 1, y, canvas); - } - - tanks_game_render_constant_cells(canvas); -} - -static void tanks_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const TanksState* tanks_state = ctx; - furi_mutex_acquire(tanks_state->mutex, FuriWaitForever); - - // Before the function is called, the state is set with the canvas_reset(canvas) - if(tanks_state->state == GameStateMenu) { - canvas_draw_icon(canvas, 0, 0, &I_TanksSplashScreen_128x64); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 124, 10, AlignRight, AlignBottom, "Single"); - canvas_draw_str_aligned(canvas, 124, 25, AlignRight, AlignBottom, "Co-op S"); - canvas_draw_str_aligned(canvas, 124, 40, AlignRight, AlignBottom, "Co-op C"); - - switch(tanks_state->menu_state) { - case MenuStateSingleMode: - canvas_draw_icon(canvas, 74, 3, &I_tank_right); - break; - case MenuStateCooperativeServerMode: - canvas_draw_icon(canvas, 74, 18, &I_tank_right); - break; - case MenuStateCooperativeClientMode: - canvas_draw_icon(canvas, 74, 33, &I_tank_right); - break; - } - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - furi_mutex_release(tanks_state->mutex); - return; - } - - // Field right border - canvas_draw_box(canvas, FIELD_WIDTH * CELL_LENGTH_PIXELS, 0, 2, SCREEN_HEIGHT_TANKS); - - // Cooperative client - if(tanks_state->mode == ModeCooperative && !tanks_state->server) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_game_render_cell(tanks_state->thisMap[x][y], x, y, canvas); - } - } - - tanks_game_render_constant_cells(canvas); - - furi_mutex_release(tanks_state->mutex); - return; - } - - // Player - // Point coordinates = tanks_state->p1->coordinates; - // const Icon *icon; - // switch (tanks_state->p1->direction) { - // case DirectionUp: - // icon = &I_tank_up; - // break; - // case DirectionDown: - // icon = &I_tank_down; - // break; - // case DirectionRight: - // icon = &I_tank_right; - // break; - // case DirectionLeft: - // icon = &I_tank_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - - // if (tanks_state->p1->live) { - // canvas_draw_icon(canvas, coordinates.x * CELL_LENGTH_PIXELS, coordinates.y * CELL_LENGTH_PIXELS - 1, icon); - // } - // - // for(int8_t x = 0; x < FIELD_WIDTH; x++) { - // for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - // switch (tanks_state->thisMap[x][y]) { - // case '-': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_wall); - // break; - // - // case '=': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_stone); - // break; - // - // case '*': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_hedgehog); - // break; - // - // case 'a': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_base); - // break; - // } - // } - // } - - // for ( - // uint8_t i = 0; - // i < 6; - // i++ - // ) { - // if (tanks_state->bots[i] != NULL) { - // const Icon *icon; - // - // switch(tanks_state->bots[i]->direction) { - // case DirectionUp: - // icon = &I_enemy_up; - // break; - // case DirectionDown: - // icon = &I_enemy_down; - // break; - // case DirectionRight: - // icon = &I_enemy_right; - // break; - // case DirectionLeft: - // icon = &I_enemy_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - // - // canvas_draw_icon( - // canvas, - // tanks_state->bots[i]->coordinates.x * CELL_LENGTH_PIXELS, - // tanks_state->bots[i]->coordinates.y * CELL_LENGTH_PIXELS - 1, - // icon); - // } - // } - - // for(int8_t x = 0; x < 100; x++) { - // if (tanks_state->projectiles[x] != NULL) { - // ProjectileState *projectile = tanks_state->projectiles[x]; - // - // if (projectile->explosion) { - // canvas_draw_icon( - // canvas, - // projectile->coordinates.x * CELL_LENGTH_PIXELS, - // projectile->coordinates.y * CELL_LENGTH_PIXELS - 1, - // &I_tank_explosion); - // continue; - // } - // - // const Icon *icon; - // - // switch(projectile->direction) { - // case DirectionUp: - // icon = &I_projectile_up; - // break; - // case DirectionDown: - // icon = &I_projectile_down; - // break; - // case DirectionRight: - // icon = &I_projectile_right; - // break; - // case DirectionLeft: - // icon = &I_projectile_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - // - // canvas_draw_icon( - // canvas, - // projectile->coordinates.x * CELL_LENGTH_PIXELS, - // projectile->coordinates.y * CELL_LENGTH_PIXELS - 1, - // icon); - // } - // } - - // Info - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - char buffer1[13]; - snprintf(buffer1, sizeof(buffer1), "live: %u", tanks_state->enemies_live); - canvas_draw_str_aligned(canvas, 127, 8, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "left: %u", tanks_state->enemies_left); - canvas_draw_str_aligned(canvas, 127, 18, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "p1 l: %u", tanks_state->p1->lives); - canvas_draw_str_aligned(canvas, 127, 28, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "p1 s: %u", tanks_state->p1->score); - canvas_draw_str_aligned(canvas, 127, 38, AlignRight, AlignBottom, buffer1); - - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2) { - snprintf(buffer1, sizeof(buffer1), "rec: %u", tanks_state->received); - canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "snt: %u", tanks_state->sent); - canvas_draw_str_aligned(canvas, 127, 58, AlignRight, AlignBottom, buffer1); - // snprintf(buffer1, sizeof(buffer1), "p2 l: %u", tanks_state->p2->lives); - // canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - // - // snprintf(buffer1, sizeof(buffer1), "p2 s: %u", tanks_state->p2->score); - // canvas_draw_str_aligned(canvas, 127, 58, AlignRight, AlignBottom, buffer1); - } - - if(tanks_state->state == GameStateCooperativeClient) { - snprintf(buffer1, sizeof(buffer1), "rec: %u", tanks_state->received); - canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - } - - // Game Over banner - if(tanks_state->state == GameStateGameOver) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - canvas_set_font(canvas, FontPrimary); - - if(tanks_state->enemies_left == 0 && tanks_state->enemies_live == 0) { - canvas_draw_str(canvas, 37, 31, "You win!"); - } else { - canvas_draw_str(canvas, 37, 31, "Game Over"); - } - - canvas_set_font(canvas, FontSecondary); - char buffer[13]; - snprintf(buffer, sizeof(buffer), "Score: %u", tanks_state->p1->score); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); - } - - // TEST start - unsigned char* data = tanks_game_serialize(tanks_state); - tanks_game_deserialize_and_render(data, canvas); - // TEST enf - - furi_mutex_release(tanks_state->mutex); -} - -static void tanks_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TanksEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tanks_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TanksEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static bool tanks_get_cell_is_free(TanksState* const tanks_state, Point point) { - // Tiles - if(tanks_state->thisMap[point.x][point.y] != ' ') { - return false; - } - - // Projectiles - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - if(tanks_state->projectiles[x]->coordinates.x == point.x && - tanks_state->projectiles[x]->coordinates.y == point.y) { - return false; - } - } - } - - // Player 1 - if(tanks_state->p1 != NULL) { - if(tanks_state->p1->coordinates.x == point.x && - tanks_state->p1->coordinates.y == point.y) { - return false; - } - } - - // Player 2 - if(tanks_state->p2 != NULL) { - if(tanks_state->p2->coordinates.x == point.x && - tanks_state->p2->coordinates.y == point.y) { - return false; - } - } - - // Bots - for(int8_t x = 0; x < 6; x++) { - if(tanks_state->bots[x] != NULL) { - if(tanks_state->bots[x]->coordinates.x == point.x && - tanks_state->bots[x]->coordinates.y == point.y) { - return false; - } - } - } - - return true; -} - -static uint8_t tanks_get_random_free_respawn_point_index( - TanksState* const tanks_state, - Point respawn_points[3]) { - uint8_t first = rand() % 3; - int8_t add = rand() % 2 ? +1 : -1; - int8_t second = first + add; - uint8_t third; - - if(second == 4) { - second = 0; - } else if(second == -1) { - second = 3; - } - - for(uint8_t i = 0; i < 3; i++) { - if(i != first && i != second) { - third = i; - } - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[first])) { - return first; - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[second])) { - return second; - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[third])) { - return third; - } - - return -1; -} - -static void tanks_game_init_game(TanksState* const tanks_state, GameState type) { - srand(DWT->CYCCNT); - - tanks_state->state = type; - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - free(tanks_state->projectiles[x]); - tanks_state->projectiles[x] = NULL; - } - } - - int8_t team_one_respawn_points_counter = 0; - int8_t team_two_respawn_points_counter = 0; - - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_state->thisMap[x][y] = ' '; - - if(thisMap[y][x] == '1') { - Point respawn = {x, y}; - tanks_state->team_one_respawn_points[team_one_respawn_points_counter++] = respawn; - } - - if(thisMap[y][x] == '2') { - Point respawn = {x, y}; - tanks_state->team_two_respawn_points[team_two_respawn_points_counter++] = respawn; - } - - if(thisMap[y][x] == '-') { - tanks_state->thisMap[x][y] = '-'; - } - - if(thisMap[y][x] == '=') { - tanks_state->thisMap[x][y] = '='; - } - - if(thisMap[y][x] == '*') { - tanks_state->thisMap[x][y] = '*'; - } - - if(thisMap[y][x] == 'a') { - tanks_state->thisMap[x][y] = 'a'; - } - } - } - - uint8_t index1 = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - Point c = { - tanks_state->team_one_respawn_points[index1].x, - tanks_state->team_one_respawn_points[index1].y}; - - PlayerState p1 = { - c, - 0, - 4, - DirectionRight, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - PlayerState* p1_state = malloc(sizeof(PlayerState)); - *p1_state = p1; - - tanks_state->p1 = p1_state; - - if(type == GameStateCooperativeServer) { - int8_t index2 = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - Point c = { - tanks_state->team_one_respawn_points[index2].x, - tanks_state->team_one_respawn_points[index2].y}; - - PlayerState p2 = { - c, - 0, - 4, - DirectionRight, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - PlayerState* p2_state = malloc(sizeof(PlayerState)); - *p2_state = p2; - - tanks_state->p2 = p2_state; - } - - tanks_state->enemies_left = 5; - tanks_state->enemies_live = 0; - tanks_state->enemies_respawn_cooldown = RESPAWN_COOLDOWN; - tanks_state->received = 0; - tanks_state->sent = 0; - - if(type == GameStateCooperativeClient) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_state->thisMap[x][y] = CellEmpty; - } - } - } -} - -static bool - tanks_game_collision(Point const next_step, bool shoot, TanksState const* const tanks_state) { - if((int8_t)next_step.x < 0 || (int8_t)next_step.y < 0) { - return true; - } - - if(next_step.x >= FIELD_WIDTH || next_step.y >= FIELD_HEIGHT) { - return true; - } - - char tile = tanks_state->thisMap[next_step.x][next_step.y]; - - if(tile == '*' && !shoot) { - return true; - } - - if(tile == '-' || tile == '=' || tile == 'a') { - return true; - } - - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - if(tanks_state->bots[i]->coordinates.x == next_step.x && - tanks_state->bots[i]->coordinates.y == next_step.y) { - return true; - } - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && - tanks_state->p1->coordinates.x == next_step.x && - tanks_state->p1->coordinates.y == next_step.y) { - return true; - } - - if(tanks_state->p2 != NULL && tanks_state->p2->live && - tanks_state->p2->coordinates.x == next_step.x && - tanks_state->p2->coordinates.y == next_step.y) { - return true; - } - - return false; -} - -static Point tanks_game_get_next_step(Point coordinates, Direction direction) { - Point next_step = {coordinates.x, coordinates.y}; - - switch(direction) { - // +-----x - // | - // | - // y - case DirectionUp: - next_step.y--; - break; - case DirectionRight: - next_step.x++; - break; - case DirectionDown: - next_step.y++; - break; - case DirectionLeft: - next_step.x--; - break; - default: - break; - } - return next_step; -} - -static uint8_t tanks_game_get_free_projectile_index(TanksState* const tanks_state) { - uint8_t freeProjectileIndex; - for(freeProjectileIndex = 0; freeProjectileIndex < 100; freeProjectileIndex++) { - if(tanks_state->projectiles[freeProjectileIndex] == NULL) { - return freeProjectileIndex; - } - } - - return 0; -} - -static void tanks_game_shoot( - TanksState* const tanks_state, - PlayerState* tank_state, - bool is_p1, - bool is_p2) { - tank_state->cooldown = SHOT_COOLDOWN; - - uint8_t freeProjectileIndex = tanks_game_get_free_projectile_index(tanks_state); - - ProjectileState* projectile_state = malloc(sizeof(ProjectileState)); - Point next_step = tanks_game_get_next_step(tank_state->coordinates, tank_state->direction); - - projectile_state->direction = tank_state->direction; - projectile_state->coordinates = next_step; - projectile_state->is_p1 = is_p1; - projectile_state->is_p2 = is_p2; - - bool crush = tanks_game_collision(projectile_state->coordinates, true, tanks_state); - projectile_state->explosion = crush; - - tanks_state->projectiles[freeProjectileIndex] = projectile_state; -} - -static void tanks_game_process_game_step(TanksState* const tanks_state) { - if(tanks_state->state == GameStateMenu) { - return; - } - - if(tanks_state->enemies_left == 0 && tanks_state->enemies_live == 0) { - tanks_state->state = GameStateGameOver; - } - - if(!tanks_state->p1->live && tanks_state->p1->lives == 0) { - tanks_state->state = GameStateGameOver; - } - - if(tanks_state->state == GameStateGameOver) { - return; - } - - if(tanks_state->p1 != NULL) { - if(!tanks_state->p1->live && tanks_state->p1->respawn_cooldown > 0) { - tanks_state->p1->respawn_cooldown--; - } - } - - // Player 1 spawn - if(tanks_state->p1 && !tanks_state->p1->live && tanks_state->p1->lives > 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - - if(index != -1) { - Point point = tanks_state->team_one_respawn_points[index]; - Point c = {point.x, point.y}; - tanks_state->p1->coordinates = c; - tanks_state->p1->live = true; - tanks_state->p1->direction = DirectionRight; - tanks_state->p1->cooldown = SHOT_COOLDOWN; - tanks_state->p1->respawn_cooldown = SHOT_COOLDOWN; - } - } - - // Player 2 spawn - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2 && - !tanks_state->p2->live && tanks_state->p2->lives > 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - - if(index != -1) { - Point point = tanks_state->team_one_respawn_points[index]; - Point c = {point.x, point.y}; - tanks_state->p2->coordinates = c; - tanks_state->p2->live = true; - tanks_state->p2->direction = DirectionRight; - tanks_state->p2->cooldown = SHOT_COOLDOWN; - tanks_state->p2->respawn_cooldown = SHOT_COOLDOWN; - } - } - - // Bot turn - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - PlayerState* bot = tanks_state->bots[i]; - if(bot->cooldown) { - bot->cooldown--; - } - - // Rotate - if(rand() % 3 == 0) { - bot->direction = (rand() % 4); - } - - // Move - if(rand() % 2 == 0) { - Point next_step = tanks_game_get_next_step(bot->coordinates, bot->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - bot->coordinates = next_step; - } - } - - // Shoot - if(bot->cooldown == 0 && rand() % 3 != 0) { - tanks_game_shoot(tanks_state, bot, false, false); - } - } - } - - // Bot spawn - if(tanks_state->enemies_respawn_cooldown) { - tanks_state->enemies_respawn_cooldown--; - } - - if(tanks_state->enemies_left > 0 && tanks_state->enemies_live <= 4 && - tanks_state->enemies_respawn_cooldown == 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_two_respawn_points); - - if(index != -1) { - tanks_state->enemies_left--; - tanks_state->enemies_live++; - tanks_state->enemies_respawn_cooldown = RESPAWN_COOLDOWN; - Point point = tanks_state->team_two_respawn_points[index]; - - Point c = {point.x, point.y}; - - PlayerState bot = { - c, - 0, - 0, - DirectionLeft, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - uint8_t freeEnemyIndex; - for(freeEnemyIndex = 0; freeEnemyIndex < 6; freeEnemyIndex++) { - if(tanks_state->bots[freeEnemyIndex] == NULL) { - break; - } - } - - PlayerState* bot_state = malloc(sizeof(PlayerState)); - *bot_state = bot; - - tanks_state->bots[freeEnemyIndex] = bot_state; - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && tanks_state->p1->moving) { - Point next_step = - tanks_game_get_next_step(tanks_state->p1->coordinates, tanks_state->p1->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - tanks_state->p1->coordinates = next_step; - } - } - - // Player 2 spawn - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2 && - tanks_state->p2->live && tanks_state->p2->moving) { - Point next_step = - tanks_game_get_next_step(tanks_state->p2->coordinates, tanks_state->p2->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - tanks_state->p2->coordinates = next_step; - } - } - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - ProjectileState* projectile = tanks_state->projectiles[x]; - Point c = projectile->coordinates; - - if(projectile->explosion) { - // Break a wall - if(tanks_state->thisMap[c.x][c.y] == '-') { - tanks_state->thisMap[c.x][c.y] = ' '; - } - - // Kill a bot - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - if(tanks_state->bots[i]->coordinates.x == c.x && - tanks_state->bots[i]->coordinates.y == c.y) { - if(projectile->is_p1) { - tanks_state->p1->score++; - } - - if(projectile->is_p2) { - tanks_state->p2->score++; - } - - // No friendly fire - if(projectile->is_p1 || projectile->is_p2) { - tanks_state->enemies_live--; - free(tanks_state->bots[i]); - tanks_state->bots[i] = NULL; - } - } - } - } - - // Destroy the flag - if(tanks_state->thisMap[c.x][c.y] == 'a') { - tanks_state->state = GameStateGameOver; - return; - } - - // Kill a player 1 - if(tanks_state->p1 != NULL) { - if(tanks_state->p1->live && tanks_state->p1->coordinates.x == c.x && - tanks_state->p1->coordinates.y == c.y) { - tanks_state->p1->live = false; - tanks_state->p1->lives--; - tanks_state->p1->respawn_cooldown = PLAYER_RESPAWN_COOLDOWN; - } - } - - // Kill a player 2 - if(tanks_state->p2 != NULL) { - if(tanks_state->p2->live && tanks_state->p2->coordinates.x == c.x && - tanks_state->p2->coordinates.y == c.y) { - tanks_state->p2->live = false; - tanks_state->p2->lives--; - tanks_state->p2->respawn_cooldown = PLAYER_RESPAWN_COOLDOWN; - } - } - - // Delete projectile - free(tanks_state->projectiles[x]); - tanks_state->projectiles[x] = NULL; - continue; - } - - Point next_step = - tanks_game_get_next_step(projectile->coordinates, projectile->direction); - bool crush = tanks_game_collision(next_step, true, tanks_state); - projectile->coordinates = next_step; - - if(crush) { - projectile->explosion = true; - } - } - } - - if(tanks_state->p1->cooldown > 0) { - tanks_state->p1->cooldown--; - } - - if(tanks_state->p2 != NULL && tanks_state->p2->cooldown > 0) { - tanks_state->p2->cooldown--; - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && tanks_state->p1->shooting && - tanks_state->p1->cooldown == 0) { - tanks_game_shoot(tanks_state, tanks_state->p1, true, false); - } - - tanks_state->p1->moving = false; - tanks_state->p1->shooting = false; - - if(tanks_state->p2 != NULL) { - tanks_state->p2->moving = false; - tanks_state->p2->shooting = false; - } -} - -int32_t tanks_game_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TanksEvent)); - - TanksState* tanks_state = malloc(sizeof(TanksState)); - - tanks_state->state = GameStateMenu; - tanks_state->menu_state = MenuStateSingleMode; - - tanks_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!tanks_state->mutex) { - FURI_LOG_E("Tanks", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tanks_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, tanks_game_render_callback, tanks_state); - view_port_input_callback_set(view_port, tanks_game_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(tanks_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 4); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - TanksEvent event; - - // Initialize network thing. - uint32_t frequency = 433920000; - size_t message_max_len = 180; - uint8_t incomingMessage[180] = {0}; - SubGhzTxRxWorker* subghz_txrx = subghz_tx_rx_worker_alloc(); - - subghz_devices_init(); - const SubGhzDevice* subghz_device = - radio_device_loader_set(NULL, SubGhzRadioDeviceTypeExternalCC1101); - - subghz_devices_reset(subghz_device); - subghz_devices_load_preset(subghz_device, FuriHalSubGhzPresetOok650Async, NULL); - - subghz_tx_rx_worker_start(subghz_txrx, subghz_device, frequency); - furi_hal_power_suppress_charge_enter(); - - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - - furi_mutex_acquire(tanks_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->menu_state = MenuStateSingleMode; - } else if(tanks_state->menu_state == MenuStateCooperativeClientMode) { - tanks_state->menu_state = MenuStateCooperativeServerMode; - } - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesUp = furi_string_alloc(); - char arr[2]; - arr[0] = GoesUp; - arr[1] = 0; - furi_string_set(goesUp, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesUp), - strlen(furi_string_get_cstr(goesUp))); - furi_string_free(goesUp); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionUp; - } - break; - case InputKeyDown: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateSingleMode) { - tanks_state->menu_state = MenuStateCooperativeServerMode; - } else if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->menu_state = MenuStateCooperativeClientMode; - } - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesDown = furi_string_alloc(); - char arr[2]; - arr[0] = GoesDown; - arr[1] = 0; - furi_string_set(goesDown, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesDown), - strlen(furi_string_get_cstr(goesDown))); - furi_string_free(goesDown); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionDown; - } - break; - case InputKeyRight: - if(!(tanks_state->state == GameStateMenu)) { - if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesRight = furi_string_alloc(); - char arr[2]; - arr[0] = GoesRight; - arr[1] = 0; - furi_string_set(goesRight, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesRight), - strlen(furi_string_get_cstr(goesRight))); - furi_string_free(goesRight); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionRight; - } - } - break; - case InputKeyLeft: - if(!(tanks_state->state == GameStateMenu)) { - if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesLeft = furi_string_alloc(); - char arr[2]; - arr[0] = GoesLeft; - arr[1] = 0; - furi_string_set(goesLeft, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesLeft), - strlen(furi_string_get_cstr(goesLeft))); - furi_string_free(goesLeft); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionLeft; - } - } - break; - case InputKeyOk: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateSingleMode) { - tanks_state->server = true; - tanks_game_init_game(tanks_state, GameStateSingle); - break; - } else if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->server = true; - tanks_game_init_game(tanks_state, GameStateCooperativeServer); - break; - } else if(tanks_state->menu_state == MenuStateCooperativeClientMode) { - tanks_state->server = false; - tanks_game_init_game(tanks_state, GameStateCooperativeClient); - break; - } - } else if(tanks_state->state == GameStateGameOver) { - tanks_game_init_game(tanks_state, tanks_state->state); - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* shoots = furi_string_alloc(); - char arr[2]; - arr[0] = Shoots; - arr[1] = 0; - furi_string_set(shoots, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(shoots), - strlen(furi_string_get_cstr(shoots))); - furi_string_free(shoots); - } else { - tanks_state->p1->shooting = true; - } - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - if(tanks_state->state == GameStateCooperativeServer) { - if(subghz_tx_rx_worker_available(subghz_txrx)) { - memset(incomingMessage, 0x00, message_max_len); - subghz_tx_rx_worker_read(subghz_txrx, incomingMessage, message_max_len); - - if(incomingMessage != NULL) { - tanks_state->received++; - - switch(incomingMessage[0]) { - case GoesUp: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionUp; - break; - case GoesRight: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionRight; - break; - case GoesDown: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionDown; - break; - case GoesLeft: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionLeft; - break; - case Shoots: - tanks_state->p2->shooting = true; - break; - default: - break; - } - } - } - - tanks_game_process_game_step(tanks_state); - - FuriString* serializedData = furi_string_alloc(); - unsigned char* data = tanks_game_serialize(tanks_state); - char arr[11 * 16 + 1]; - - for(uint8_t i = 0; i < 11 * 16; i++) { - arr[i] = data[i]; - } - - arr[11 * 16] = 0; - - furi_string_set(serializedData, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(serializedData), - strlen(furi_string_get_cstr(serializedData))); - furi_string_free(serializedData); - tanks_state->sent++; - } else if(tanks_state->state == GameStateSingle) { - tanks_game_process_game_step(tanks_state); - } else if(tanks_state->state == GameStateCooperativeClient) { - if(subghz_tx_rx_worker_available(subghz_txrx)) { - memset(incomingMessage, 0x00, message_max_len); - subghz_tx_rx_worker_read(subghz_txrx, incomingMessage, message_max_len); - - tanks_state->received++; - - tanks_game_deserialize_and_write_to_state( - (unsigned char*)incomingMessage, tanks_state); - } - } - } - } else { - // event timeout - } - - view_port_update(view_port); - furi_mutex_release(tanks_state->mutex); - furi_delay_ms(1); - } - - furi_delay_ms(10); - furi_hal_power_suppress_charge_exit(); - - if(subghz_tx_rx_worker_is_running(subghz_txrx)) { - subghz_tx_rx_worker_stop(subghz_txrx); - subghz_tx_rx_worker_free(subghz_txrx); - } - - subghz_devices_deinit(); - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tanks_state->mutex); - - if(tanks_state->p1 != NULL) { - free(tanks_state->p1); - } - - if(tanks_state->p2 != NULL) { - free(tanks_state->p2); - } - - free(tanks_state); - - return 0; -} diff --git a/applications/external/tetris_game/application.fam b/applications/external/tetris_game/application.fam deleted file mode 100644 index 0766daf1e..000000000 --- a/applications/external/tetris_game/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="tetris", - name="Tetris", - apptype=FlipperAppType.EXTERNAL, - entry_point="tetris_game_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="tetris_10px.png", - fap_category="Games", - fap_author="@xMasterX & @jeffplang", - fap_version="1.0", - fap_description="Tetris Game", -) diff --git a/applications/external/tetris_game/tetris_10px.png b/applications/external/tetris_game/tetris_10px.png deleted file mode 100644 index e4886d835..000000000 Binary files a/applications/external/tetris_game/tetris_10px.png and /dev/null differ diff --git a/applications/external/tetris_game/tetris_game.c b/applications/external/tetris_game/tetris_game.c deleted file mode 100644 index 95770e045..000000000 --- a/applications/external/tetris_game/tetris_game.c +++ /dev/null @@ -1,478 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BORDER_OFFSET 1 -#define MARGIN_OFFSET 3 -#define BLOCK_HEIGHT 6 -#define BLOCK_WIDTH 6 - -#define FIELD_WIDTH 11 -#define FIELD_HEIGHT 24 - -#define MAX_FALL_SPEED 500 -#define MIN_FALL_SPEED 100 - -typedef struct Point { - // Also used for offset data, which is sometimes negative - int8_t x, y; -} Point; - -// Rotation logic taken from -// https://www.youtube.com/watch?v=yIpk5TJ_uaI -typedef enum { OffsetTypeCommon, OffsetTypeI, OffsetTypeO } OffsetType; - -// Since we only support rotating clockwise, these are actual translation values, -// not values to be subtracted to get translation values - -static const Point rotOffsetTranslation[3][4][5] = { - {{{0, 0}, {-1, 0}, {-1, -1}, {0, 2}, {-1, 2}}, - {{0, 0}, {1, 0}, {1, 1}, {0, -2}, {1, -2}}, - {{0, 0}, {1, 0}, {1, -1}, {0, 2}, {1, 2}}, - {{0, 0}, {-1, 0}, {-1, 1}, {0, -2}, {-1, -2}}}, - {{{1, 0}, {-1, 0}, {2, 0}, {-1, 1}, {2, -2}}, - {{0, 1}, {-1, 1}, {2, 1}, {-1, -1}, {2, 2}}, - {{-1, 0}, {1, 0}, {-2, 0}, {1, -1}, {-2, 2}}, - {{0, -1}, {1, -1}, {-2, -1}, {1, 1}, {-2, -2}}}, - {{{0, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{-1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}}}; - -typedef struct { - Point p[4]; - uint8_t rotIdx; - OffsetType offsetType; -} Piece; - -// Shapes @ spawn locations, rotation point first -static Piece shapes[] = { - {.p = {{5, 1}, {4, 0}, {5, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // Z - {.p = {{5, 1}, {4, 1}, {5, 0}, {6, 0}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // S - {.p = {{5, 1}, {4, 1}, {6, 1}, {6, 0}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // L - {.p = {{5, 1}, {4, 0}, {4, 1}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // J - {.p = {{5, 1}, {4, 1}, {5, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // T - {.p = {{5, 1}, {4, 1}, {6, 1}, {7, 1}}, .rotIdx = 0, .offsetType = OffsetTypeI}, // I - {.p = {{5, 1}, {5, 0}, {6, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeO} // O -}; - -typedef enum { GameStatePlaying, GameStateGameOver } GameState; - -typedef struct { - bool playField[FIELD_HEIGHT][FIELD_WIDTH]; - Piece currPiece; - uint16_t numLines; - uint16_t fallSpeed; - GameState gameState; - FuriTimer* timer; - FuriMutex* mutex; -} TetrisState; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} TetrisEvent; - -static void tetris_game_draw_border(Canvas* const canvas) { - canvas_draw_line(canvas, 0, 0, 0, 127); - canvas_draw_line(canvas, 0, 127, 63, 127); - canvas_draw_line(canvas, 63, 127, 63, 0); - - canvas_draw_line(canvas, 2, 0, 2, 125); - canvas_draw_line(canvas, 2, 125, 61, 125); - canvas_draw_line(canvas, 61, 125, 61, 0); -} - -static void tetris_game_draw_playfield(Canvas* const canvas, const TetrisState* tetris_state) { - // Playfield: 11 x 24 - - for(int y = 0; y < FIELD_HEIGHT; y++) { - for(int x = 0; x < FIELD_WIDTH; x++) { - if(tetris_state->playField[y][x]) { - uint16_t xOffset = x * 5; - uint16_t yOffset = y * 5; - - canvas_draw_rframe( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset, - BORDER_OFFSET + MARGIN_OFFSET + yOffset - 1, - BLOCK_WIDTH, - BLOCK_HEIGHT, - 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 2, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 3, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 2, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 2); - } - } - } -} - -static void tetris_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const TetrisState* tetris_state = ctx; - furi_mutex_acquire(tetris_state->mutex, FuriWaitForever); - - tetris_game_draw_border(canvas); - tetris_game_draw_playfield(canvas, tetris_state); - - // Show score on the game field - if(tetris_state->gameState == GameStatePlaying) { - char buffer2[6]; - snprintf(buffer2, sizeof(buffer2), "%u", tetris_state->numLines); - canvas_draw_str_aligned(canvas, 58, 10, AlignRight, AlignBottom, buffer2); - } - - if(tetris_state->gameState == GameStateGameOver) { - // 128 x 64 - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 1, 52, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 1, 52, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 4, 63, "Game Over"); - - char buffer[13]; - snprintf(buffer, sizeof(buffer), "Lines: %u", tetris_state->numLines); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 32, 73, AlignCenter, AlignBottom, buffer); - } - furi_mutex_release(tetris_state->mutex); -} - -static void tetris_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TetrisEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tetris_game_init_state(TetrisState* tetris_state) { - tetris_state->gameState = GameStatePlaying; - tetris_state->numLines = 0; - tetris_state->fallSpeed = MAX_FALL_SPEED; - memset(tetris_state->playField, 0, sizeof(tetris_state->playField)); - - memcpy(&tetris_state->currPiece, &shapes[rand() % 7], sizeof(tetris_state->currPiece)); - - furi_timer_start(tetris_state->timer, tetris_state->fallSpeed); -} - -static void tetris_game_remove_curr_piece(TetrisState* tetris_state) { - for(int i = 0; i < 4; i++) { - uint8_t x = tetris_state->currPiece.p[i].x; - uint8_t y = tetris_state->currPiece.p[i].y; - - tetris_state->playField[y][x] = false; - } -} - -static void tetris_game_render_curr_piece(TetrisState* tetris_state) { - for(int i = 0; i < 4; i++) { - uint8_t x = tetris_state->currPiece.p[i].x; - uint8_t y = tetris_state->currPiece.p[i].y; - - tetris_state->playField[y][x] = true; - } -} - -static void tetris_game_rotate_shape(Point currShape[], Point newShape[]) { - // Copy shape data - for(int i = 0; i < 4; i++) { - newShape[i] = currShape[i]; - } - - for(int i = 1; i < 4; i++) { - int8_t relX = currShape[i].x - currShape[0].x; - int8_t relY = currShape[i].y - currShape[0].y; - - // Matrix rotation thing - int8_t newRelX = (relX * 0) + (relY * -1); - int8_t newRelY = (relX * 1) + (relY * 0); - - newShape[i].x = currShape[0].x + newRelX; - newShape[i].y = currShape[0].y + newRelY; - } -} - -static void tetris_game_apply_kick(Point points[], Point kick) { - for(int i = 0; i < 4; i++) { - points[i].x += kick.x; - points[i].y += kick.y; - } -} - -static bool tetris_game_is_valid_pos(TetrisState* tetris_state, Point* shape) { - for(int i = 0; i < 4; i++) { - if(shape[i].x < 0 || shape[i].x > (FIELD_WIDTH - 1) || - tetris_state->playField[shape[i].y][shape[i].x] == true) { - return false; - } - } - return true; -} - -static void tetris_game_try_rotation(TetrisState* tetris_state, Piece* newPiece) { - uint8_t currRotIdx = tetris_state->currPiece.rotIdx; - - Point* rotatedShape = malloc(sizeof(Point) * 4); - Point* kickedShape = malloc(sizeof(Point) * 4); - - memcpy(rotatedShape, &tetris_state->currPiece.p, sizeof(tetris_state->currPiece.p)); - - tetris_game_rotate_shape(tetris_state->currPiece.p, rotatedShape); - - for(int i = 0; i < 5; i++) { - memcpy(kickedShape, rotatedShape, (sizeof(Point) * 4)); - tetris_game_apply_kick( - kickedShape, rotOffsetTranslation[newPiece->offsetType][currRotIdx][i]); - - if(tetris_game_is_valid_pos(tetris_state, kickedShape)) { - memcpy(&newPiece->p, kickedShape, sizeof(newPiece->p)); - newPiece->rotIdx = (newPiece->rotIdx + 1) % 4; - break; - } - } - free(rotatedShape); - free(kickedShape); -} - -static bool tetris_game_row_is_line(bool row[]) { - for(int i = 0; i < FIELD_WIDTH; i++) { - if(row[i] == false) return false; - } - return true; -} - -static void - tetris_game_check_for_lines(TetrisState* tetris_state, uint8_t* lines, uint8_t* numLines) { - for(int i = 0; i < FIELD_HEIGHT; i++) { - if(tetris_game_row_is_line(tetris_state->playField[i])) { - *(lines++) = i; - *numLines += 1; - } - } -} - -static bool tetris_game_piece_at_bottom(TetrisState* tetris_state, Piece* newPiece) { - for(int i = 0; i < 4; i++) { - Point* pos = (Point*)&newPiece->p; - if(pos[i].y >= FIELD_HEIGHT || tetris_state->playField[pos[i].y][pos[i].x] == true) { - return true; - } - } - return false; -} - -static void tetris_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TetrisEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void - tetris_game_process_step(TetrisState* tetris_state, Piece* newPiece, bool wasDownMove) { - if(tetris_state->gameState == GameStateGameOver) return; - - tetris_game_remove_curr_piece(tetris_state); - - if(wasDownMove) { - if(tetris_game_piece_at_bottom(tetris_state, newPiece)) { - furi_timer_stop(tetris_state->timer); - - tetris_game_render_curr_piece(tetris_state); - uint8_t numLines = 0; - uint8_t lines[] = {0, 0, 0, 0}; - uint16_t nextFallSpeed; - - tetris_game_check_for_lines(tetris_state, lines, &numLines); - if(numLines > 0) { - for(int i = 0; i < numLines; i++) { - // zero out row - for(int j = 0; j < FIELD_WIDTH; j++) { - tetris_state->playField[lines[i]][j] = false; - } - // move all above rows down - for(int k = lines[i]; k >= 0; k--) { - for(int m = 0; m < FIELD_WIDTH; m++) { - tetris_state->playField[k][m] = - (k == 0) ? false : tetris_state->playField[k - 1][m]; - } - } - } - - uint16_t oldNumLines = tetris_state->numLines; - tetris_state->numLines += numLines; - if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - nextFallSpeed = - tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); - if(nextFallSpeed >= MIN_FALL_SPEED) { - tetris_state->fallSpeed = nextFallSpeed; - } - } - } - - // Check for game over - Piece* spawnedPiece = &shapes[rand() % 7]; - if(!tetris_game_is_valid_pos(tetris_state, spawnedPiece->p)) { - tetris_state->gameState = GameStateGameOver; - } else { - memcpy(&tetris_state->currPiece, spawnedPiece, sizeof(tetris_state->currPiece)); - furi_timer_start(tetris_state->timer, tetris_state->fallSpeed); - } - } - } - - if(tetris_game_is_valid_pos(tetris_state, newPiece->p)) { - memcpy(&tetris_state->currPiece, newPiece, sizeof(tetris_state->currPiece)); - } - - tetris_game_render_curr_piece(tetris_state); -} - -int32_t tetris_game_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TetrisEvent)); - - TetrisState* tetris_state = malloc(sizeof(TetrisState)); - - tetris_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!tetris_state->mutex) { - FURI_LOG_E("TetrisGame", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tetris_state); - return 255; - } - - // Not doing this eventually causes issues with TimerSvc due to not sleeping/yielding enough in this task - furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated); - - ViewPort* view_port = view_port_alloc(); - view_port_set_orientation(view_port, ViewPortOrientationVertical); - view_port_draw_callback_set(view_port, tetris_game_render_callback, tetris_state); - view_port_input_callback_set(view_port, tetris_game_input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - tetris_state->timer = - furi_timer_alloc(tetris_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - tetris_game_init_state(tetris_state); - - TetrisEvent event; - - Piece* newPiece = malloc(sizeof(Piece)); - uint8_t downRepeatCounter = 0; - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - for(bool processing = true; processing;) { - // This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 10U); - - furi_mutex_acquire(tetris_state->mutex, FuriWaitForever); - - memcpy(newPiece, &tetris_state->currPiece, sizeof(tetris_state->currPiece)); - bool wasDownMove = false; - - if(!furi_hal_gpio_read(&gpio_button_right)) { - if(downRepeatCounter > 3) { - for(int i = 0; i < 4; i++) { - newPiece->p[i].y += 1; - } - downRepeatCounter = 0; - wasDownMove = true; - } else { - downRepeatCounter++; - } - } - - if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress || event.input.type == InputTypeLong || - event.input.type == InputTypeRepeat) { - switch(event.input.key) { - case InputKeyUp: - break; - case InputKeyDown: - break; - case InputKeyRight: - for(int i = 0; i < 4; i++) { - newPiece->p[i].x += 1; - } - break; - case InputKeyLeft: - for(int i = 0; i < 4; i++) { - newPiece->p[i].x -= 1; - } - break; - case InputKeyOk: - if(tetris_state->gameState == GameStatePlaying) { - tetris_game_remove_curr_piece(tetris_state); - tetris_game_try_rotation(tetris_state, newPiece); - tetris_game_render_curr_piece(tetris_state); - } else { - tetris_game_init_state(tetris_state); - } - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - // TODO: This is inverted. it returns true when the button is not pressed. - // see macro in input.c and do that - if(furi_hal_gpio_read(&gpio_button_right)) { - for(int i = 0; i < 4; i++) { - newPiece->p[i].y += 1; - } - wasDownMove = true; - } - } - } - - tetris_game_process_step(tetris_state, newPiece, wasDownMove); - - view_port_update(view_port); - furi_mutex_release(tetris_state->mutex); - } - - furi_timer_free(tetris_state->timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tetris_state->mutex); - furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal); - free(newPiece); - free(tetris_state); - - return 0; -} diff --git a/applications/external/tictactoe_game/application.fam b/applications/external/tictactoe_game/application.fam deleted file mode 100644 index 48d904d0e..000000000 --- a/applications/external/tictactoe_game/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="tictactoe", - name="Tic Tac Toe", - apptype=FlipperAppType.EXTERNAL, - entry_point="tictactoe_game_app", - requires=["gui"], - stack_size=1 * 1024, - fap_icon="tictactoe_10px.png", - fap_category="Games", - fap_author="@xMasterX & @gotnull", - fap_version="1.0", - fap_description="Tic Tac Toe game, for 2 players, play on one device", -) diff --git a/applications/external/tictactoe_game/tictactoe_10px.png b/applications/external/tictactoe_game/tictactoe_10px.png deleted file mode 100644 index 41ca1d973..000000000 Binary files a/applications/external/tictactoe_game/tictactoe_10px.png and /dev/null differ diff --git a/applications/external/tictactoe_game/tictactoe_game.c b/applications/external/tictactoe_game/tictactoe_game.c deleted file mode 100644 index 6ad076a4a..000000000 --- a/applications/external/tictactoe_game/tictactoe_game.c +++ /dev/null @@ -1,387 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define TAG "TicTacToe" - -typedef enum { EventTypeTick, EventTypeKey } EventType; - -typedef struct { - FuriMutex* mutex; - FuriTimer* timer; - uint8_t selBoxX; - uint8_t selBoxY; - - uint8_t selX; - uint8_t selY; - - uint16_t scoreX; - uint16_t scoreO; - - char player; - - char field[3][3]; - bool fieldx[3][3]; - - uint8_t coords[3]; - - bool button_state; - -} TicTacToeState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -void drawCross(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_draw_line(canvas, x, y, x + 9, y + 9); // top left - bottom right slash - canvas_draw_line(canvas, x + 9, y, x, y + 9); // down left - top right slash -} - -void drawCircle(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_draw_circle(canvas, x + 4, y + 5, 5); -} - -void player_switch(TicTacToeState* ts) { - if(ts->player == 'O') { - ts->player = 'X'; - } else if(ts->player == 'X') { - ts->player = 'O'; - } -} - -void tictactoe_draw(Canvas* canvas, TicTacToeState* ts) { - // Draws the game field - canvas_draw_frame(canvas, 0, 0, 64, 64); // frame - canvas_draw_line(canvas, 0, 21, 63, 21); // horizontal line - canvas_draw_line(canvas, 0, 42, 63, 42); // horizontal line - canvas_draw_line(canvas, 21, 0, 21, 63); // vertical line - canvas_draw_line(canvas, 42, 0, 42, 63); // vertical line - - // Draws the game field elements (X or O) - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - if(ts->field[i][j] == 'O') { - drawCircle(canvas, ts->coords[i], ts->coords[j]); - } else if(ts->field[i][j] == 'X') { - drawCross(canvas, ts->coords[i], ts->coords[j]); - } - } - } - - // Draws the selection box - if(ts->selX == 1) { - ts->selBoxX = 1; - } else if(ts->selX == 2) { - ts->selBoxX = 22; - } else if(ts->selX == 3) { - ts->selBoxX = 43; - } - - if(ts->selY == 1) { - ts->selBoxY = 1; - } else if(ts->selY == 2) { - ts->selBoxY = 22; - } else if(ts->selY == 3) { - ts->selBoxY = 43; - } - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, ts->selBoxX, ts->selBoxY, 20, 20); - canvas_draw_frame(canvas, ts->selBoxX + 1, ts->selBoxY + 1, 18, 18); - - // Draws the sidebar - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 81, 10, "SCORE"); - canvas_draw_str(canvas, 75, 24, "X:"); - - char scoreXBuffer[10]; - snprintf(scoreXBuffer, sizeof(scoreXBuffer), "%d", ts->scoreX); - canvas_draw_str(canvas, 88, 24, scoreXBuffer); - canvas_draw_str(canvas, 75, 35, "O:"); - - char scoreOBuffer[10]; - snprintf(scoreOBuffer, sizeof(scoreOBuffer), "%d", ts->scoreO); - canvas_draw_str(canvas, 88, 35, scoreOBuffer); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 75, 46, "Player:"); - - if(ts->player == 'X') { - drawCross(canvas, 93, 50); - } else if(ts->player == 'O') { - drawCircle(canvas, 93, 50); - } -} - -void clear_game_field(TicTacToeState* ts) { - // Clears the game field arrays - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - ts->field[i][j] = ' '; - ts->fieldx[i][j] = false; - } - } - - ts->selX = 2; // Centers the selection box on X axis - ts->selY = 2; // Centers the selection box on Y axis -} - -void reset_game_data(TicTacToeState* ts) { - ts->scoreO = 0; - ts->scoreX = 0; - ts->player = 'X'; -} - -void draw_win(Canvas* canvas, char player, TicTacToeState* ts) { - // Handles the score table - if(player == 'X') { - ts->scoreX++; - } else if(player == 'O') { - ts->scoreO++; - } - - // Switches the players - player_switch(ts); - - // Draws the board with players switched - tictactoe_draw(canvas, ts); - - // Clear the game field - clear_game_field(ts); - - // Draw the new board - tictactoe_draw(canvas, ts); -} - -static void tictactoe_state_init(TicTacToeState* tictactoe_state) { - // Set the initial game state - tictactoe_state->selX = 2; - tictactoe_state->selY = 2; - tictactoe_state->player = 'X'; - tictactoe_state->coords[0] = 6; - tictactoe_state->coords[1] = 27; - tictactoe_state->coords[2] = 48; - tictactoe_state->button_state = false; - - clear_game_field(tictactoe_state); - - reset_game_data(tictactoe_state); -} - -static void tictactoe_draw_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - TicTacToeState* ticst = ctx; - furi_mutex_acquire(ticst->mutex, FuriWaitForever); - - if(ticst->selX > 3) { - ticst->selX = 3; - } else if(ticst->selX < 1) { - ticst->selX = 1; - } - - if(ticst->selY > 3) { - ticst->selY = 3; - } else if(ticst->selY < 1) { - ticst->selY = 1; - } - - // Assigns the game field elements their value (X or O) when the OK button is pressed - if(ticst->button_state) { - ticst->button_state = false; - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - if((ticst->selX == i + 1) && (ticst->selY == j + 1) && - (ticst->fieldx[i][j] == false)) { - if(ticst->player == 'X') { - ticst->field[i][j] = 'X'; - ticst->fieldx[i][j] = true; - player_switch(ticst); - } else if(ticst->player == 'O') { - ticst->field[i][j] = 'O'; - ticst->fieldx[i][j] = true; - player_switch(ticst); - } - } - } - } - } - - // Checks the game field for winning combinations - if((ticst->field[0][0] == 'X') && (ticst->field[1][0] == 'X') && (ticst->field[2][0] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][1] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[2][1] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][2] == 'X') && (ticst->field[1][2] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'X') && (ticst->field[0][1] == 'X') && - (ticst->field[0][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[1][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[1][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[2][0] == 'X') && (ticst->field[2][1] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[2][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[0][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[1][0] == 'O') && - (ticst->field[2][0] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][1] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[2][1] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][2] == 'O') && (ticst->field[1][2] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[0][1] == 'O') && - (ticst->field[0][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[1][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[1][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[2][0] == 'O') && (ticst->field[2][1] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[2][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[0][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->fieldx[0][0] == true) && (ticst->fieldx[0][1] == true) && - (ticst->fieldx[0][2] == true) && (ticst->fieldx[1][0] == true) && - (ticst->fieldx[1][1] == true) && (ticst->fieldx[1][2] == true) && - (ticst->fieldx[2][0] == true) && (ticst->fieldx[2][1] == true) && - (ticst->fieldx[2][2] == true)) { - draw_win(canvas, 'T', ticst); - } - - tictactoe_draw(canvas, ticst); - - furi_mutex_release(ticst->mutex); -} - -static void tictactoe_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tictactoe_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t tictactoe_game_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - TicTacToeState* tictactoe_state = malloc(sizeof(TicTacToeState)); - - tictactoe_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - - if(!tictactoe_state->mutex) { - FURI_LOG_E(TAG, "Cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tictactoe_state); - return 255; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, tictactoe_draw_callback, tictactoe_state); - view_port_input_callback_set(view_port, tictactoe_input_callback, event_queue); - - tictactoe_state->timer = - furi_timer_alloc(tictactoe_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(tictactoe_state->timer, furi_kernel_get_tick_frequency() / 22); - - tictactoe_state_init(tictactoe_state); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(tictactoe_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // Key events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyBack: - processing = false; - break; - case InputKeyRight: - tictactoe_state->selX++; - break; - case InputKeyLeft: - tictactoe_state->selX--; - break; - case InputKeyUp: - tictactoe_state->selY--; - break; - case InputKeyDown: - tictactoe_state->selY++; - break; - case InputKeyOk: - tictactoe_state->button_state = true; - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(tictactoe_state->mutex); - } - - furi_timer_free(tictactoe_state->timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tictactoe_state->mutex); - free(tictactoe_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/unitemp/LICENSE.md b/applications/external/unitemp/LICENSE.md deleted file mode 100644 index f288702d2..000000000 --- a/applications/external/unitemp/LICENSE.md +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/applications/external/unitemp/Sensors.c b/applications/external/unitemp/Sensors.c deleted file mode 100644 index 33dd3fa88..000000000 --- a/applications/external/unitemp/Sensors.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "Sensors.h" -#include - -//Порты ввода/вывода, которые не были обозначены в общем списке -const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA}; -const GpioPin SIO_12 = {.pin = LL_GPIO_PIN_13, .port = GPIOA}; -const GpioPin TX_13 = {.pin = LL_GPIO_PIN_6, .port = GPIOB}; -const GpioPin RX_14 = {.pin = LL_GPIO_PIN_7, .port = GPIOB}; - -//Количество доступных портов ввода/вывода -#define GPIO_ITEMS (sizeof(GPIOList) / sizeof(GPIO)) -//Количество интерфейсов -#define INTERFACES_TYPES_COUNT (int)(sizeof(interfaces) / sizeof(const Interface*)) -//Количество типов датчиков -#define SENSOR_TYPES_COUNT (int)(sizeof(sensorTypes) / sizeof(const SensorType*)) - -//Перечень достуных портов ввода/вывода -static const GPIO GPIOList[] = { - {2, "2 (A7)", &gpio_ext_pa7}, - {3, "3 (A6)", &gpio_ext_pa6}, - {4, "4 (A4)", &gpio_ext_pa4}, - {5, "5 (B3)", &gpio_ext_pb3}, - {6, "6 (B2)", &gpio_ext_pb2}, - {7, "7 (C3)", &gpio_ext_pc3}, - {10, " 10(SWC) ", &SWC_10}, - {12, "12 (SIO)", &SIO_12}, - {13, "13 (TX)", &TX_13}, - {14, "14 (RX)", &RX_14}, - {15, "15 (C1)", &gpio_ext_pc1}, - {16, "16 (C0)", &gpio_ext_pc0}, - {17, "17 (1W)", &gpio_ibutton}}; - -//Список интерфейсов, которые прикреплены к GPIO (определяется индексом) -//NULL - порт свободен, указатель на интерфейс - порт занят этим интерфейсом -static const Interface* gpio_interfaces_list[GPIO_ITEMS] = {0}; - -const Interface SINGLE_WIRE = { - .name = "Single wire", - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .updater = unitemp_singlewire_update}; -const Interface I2C = { - .name = "I2C", - .allocator = unitemp_I2C_sensor_alloc, - .mem_releaser = unitemp_I2C_sensor_free, - .updater = unitemp_I2C_sensor_update}; -const Interface ONE_WIRE = { - .name = "One wire", - .allocator = unitemp_onewire_sensor_alloc, - .mem_releaser = unitemp_onewire_sensor_free, - .updater = unitemp_onewire_sensor_update}; -const Interface SPI = { - .name = "SPI", - .allocator = unitemp_spi_sensor_alloc, - .mem_releaser = unitemp_spi_sensor_free, - .updater = unitemp_spi_sensor_update}; - -//Перечень интерфейсов подключения -//static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE, &SPI}; -//Перечень датчиков -static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22, - &Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10, - &SHT30, &GXHT30, &LM75, &HDC1080, &BMP180, - &BMP280, &BME280, &BME680, &MAX31855, &MAX6675, - &SCD30, &SCD40}; - -const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) { - if(index > SENSOR_TYPES_COUNT) return NULL; - return sensorTypes[index]; -} - -const SensorType* unitemp_sensors_getTypeFromStr(char* str) { - UNUSED(str); - if(str == NULL) return NULL; - for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) { - if(!strcmp(str, sensorTypes[i]->typename)) { - return sensorTypes[i]; - } - } - return NULL; -} - -uint8_t unitemp_sensors_getTypesCount(void) { - return SENSOR_TYPES_COUNT; -} -const SensorType** unitemp_sensors_getTypes(void) { - return sensorTypes; -} - -int unitemp_getIntFromType(const SensorType* type) { - for(int i = 0; i < SENSOR_TYPES_COUNT; i++) { - if(!strcmp(type->typename, sensorTypes[i]->typename)) { - return i; - } - } - return 255; -} -const GPIO* unitemp_gpio_getFromInt(uint8_t name) { - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].num == name) { - return &GPIOList[i]; - } - } - return NULL; -} - -const GPIO* unitemp_gpio_getFromIndex(uint8_t index) { - return &GPIOList[index]; -} - -uint8_t unitemp_gpio_toInt(const GPIO* gpio) { - if(gpio == NULL) return 255; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].pin->pin == gpio->pin->pin && GPIOList[i].pin->port == gpio->pin->port) { - return GPIOList[i].num; - } - } - return 255; -} - -uint8_t unitemp_gpio_to_index(const GpioPin* gpio) { - if(gpio == NULL) return 255; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].pin->pin == gpio->pin && GPIOList[i].pin->port == gpio->port) { - return i; - } - } - return 255; -} - -uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport) { - uint8_t aviable_ports_count = 0; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - //Проверка для one wire - if(interface == &ONE_WIRE) { - if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE)) || - (unitemp_gpio_getFromIndex(i) == extraport)) { - aviable_ports_count++; - } - } - - //Проверка для single wire - if(interface == &SINGLE_WIRE || interface == &SPI) { - if(gpio_interfaces_list[i] == NULL || (unitemp_gpio_getFromIndex(i) == extraport)) { - aviable_ports_count++; - } - } - - if(interface == &I2C) { - //У I2C два фиксированых порта - return 0; - } - } - return aviable_ports_count; -} - -void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface) { - uint8_t i = unitemp_gpio_to_index(gpio->pin); - if(i == 255) return; - gpio_interfaces_list[i] = interface; -} - -void unitemp_gpio_unlock(const GPIO* gpio) { - uint8_t i = unitemp_gpio_to_index(gpio->pin); - if(i == 255) return; - gpio_interfaces_list[i] = NULL; -} - -const GPIO* - unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport) { - //Проверка для I2C - if(interface == &I2C) { - if((gpio_interfaces_list[10] == NULL || gpio_interfaces_list[10] == &I2C) && - (gpio_interfaces_list[11] == NULL || gpio_interfaces_list[11] == &I2C)) { - //Возврат истины - return unitemp_gpio_getFromIndex(0); - } else { - //Возврат лжи - return NULL; - } - } - if(interface == &SPI) { - if(!((gpio_interfaces_list[0] == NULL || gpio_interfaces_list[0] == &SPI) && - (gpio_interfaces_list[1] == NULL || gpio_interfaces_list[1] == &SPI) && - (gpio_interfaces_list[3] == NULL || gpio_interfaces_list[3] == &SPI))) { - return NULL; - } - } - - uint8_t aviable_index = 0; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - //Проверка для one wire - if(interface == &ONE_WIRE) { - if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE)) || - (unitemp_gpio_getFromIndex(i) == extraport)) { - if(aviable_index == index) { - return unitemp_gpio_getFromIndex(i); - } else { - aviable_index++; - } - } - } - //Проверка для single wire - if(interface == &SINGLE_WIRE || interface == &SPI) { - if(gpio_interfaces_list[i] == NULL || unitemp_gpio_getFromIndex(i) == extraport) { - if(aviable_index == index) { - return unitemp_gpio_getFromIndex(i); - } else { - aviable_index++; - } - } - } - } - - return NULL; -} - -void unitemp_sensor_delete(Sensor* sensor) { - for(uint8_t i = 0; i < app->sensors_count; i++) { - if(app->sensors[i] == sensor) { - app->sensors[i]->status = UT_SENSORSTATUS_INACTIVE; - unitemp_sensors_save(); - unitemp_sensors_reload(); - return; - } - } -} - -Sensor* unitemp_sensor_getActive(uint8_t index) { - uint8_t aviable_index = 0; - for(uint8_t i = 0; i < app->sensors_count; i++) { - if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) { - if(aviable_index == index) { - return app->sensors[i]; - } else { - aviable_index++; - } - } - } - return NULL; -} - -uint8_t unitemp_sensors_getCount(void) { - if(app->sensors == NULL) return 0; - return app->sensors_count; -} - -uint8_t unitemp_sensors_getActiveCount(void) { - if(app->sensors == NULL) return 0; - uint8_t counter = 0; - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) counter++; - } - return counter; -} - -void unitemp_sensors_add(Sensor* sensor) { - app->sensors = - (Sensor**)realloc(app->sensors, (unitemp_sensors_getCount() + 1) * sizeof(Sensor*)); - app->sensors[unitemp_sensors_getCount()] = sensor; - app->sensors_count++; -} - -bool unitemp_sensors_load(void) { - UNITEMP_DEBUG("Loading sensors..."); - - //Выделение памяти на поток - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS); - - //Открытие потока к файлу с датчиками - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { - if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) { - FURI_LOG_W(APP_NAME, "Missing sensors file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } else { - FURI_LOG_E( - APP_NAME, - "An error occurred while loading the sensors file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - } - - //Вычисление размера файла - uint16_t file_size = stream_size(app->file_stream); - //Если файл пустой, то: - if(file_size == (uint8_t)0) { - FURI_LOG_W(APP_NAME, "Sensors file is empty"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - //Выделение памяти под загрузку файла - uint8_t* file_buf = malloc(file_size); - //Опустошение буфера файла - memset(file_buf, 0, file_size); - //Загрузка файла - if(stream_read(app->file_stream, file_buf, file_size) != file_size) { - //Выход при ошибке чтения - FURI_LOG_E(APP_NAME, "Error reading sensors file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - free(file_buf); - return false; - } - - //Указатель на начало строки - FuriString* file = furi_string_alloc_set_str((char*)file_buf); - //Сколько байт до конца строки - size_t line_end = 0; - - while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { - //Имя датчика - char name[11] = {0}; - //Тип датчика - char type[11] = {0}; - //Смещение по температуре - int temp_offset = 0; - //Смещение по строке для отделения аргументов - int offset = 0; - //Чтение из строки - sscanf(((char*)(file_buf + line_end)), "%s %s %d %n", name, type, &temp_offset, &offset); - //Ограничение длины имени - name[10] = '\0'; - - //Замена ? на пробел - for(uint8_t i = 0; i < 10; i++) { - if(name[i] == '?') name[i] = ' '; - } - - char* args = ((char*)(file_buf + line_end + offset)); - const SensorType* stype = unitemp_sensors_getTypeFromStr(type); - - //Проверка типа датчика - if(stype != NULL && sizeof(name) > 0 && sizeof(name) <= 11) { - Sensor* sensor = - unitemp_sensor_alloc(name, unitemp_sensors_getTypeFromStr(type), args); - if(sensor != NULL) { - sensor->temp_offset = temp_offset; - unitemp_sensors_add(sensor); - } else { - FURI_LOG_E(APP_NAME, "Failed sensor (%s:%s) mem allocation", name, type); - } - } else { - FURI_LOG_E(APP_NAME, "Unsupported sensor name (%s) or sensor type (%s)", name, type); - } - //Вычисление конца строки - line_end = furi_string_search_char(file, '\n', line_end + 1); - } - - free(file_buf); - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Sensors have been successfully loaded"); - return true; -} - -bool unitemp_sensors_save(void) { - UNITEMP_DEBUG("Saving sensors..."); - - //Выделение памяти для потока - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS); - //Создание папки плагина - storage_common_mkdir(app->storage, APP_PATH_FOLDER); - //Открытие потока - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { - FURI_LOG_E( - APP_NAME, - "An error occurred while saving the sensors file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - - //Сохранение датчиков - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - Sensor* sensor = unitemp_sensor_getActive(i); - //Замена пробела на ? - for(uint8_t i = 0; i < 10; i++) { - if(sensor->name[i] == ' ') sensor->name[i] = '?'; - } - - stream_write_format( - app->file_stream, - "%s %s %d ", - sensor->name, - sensor->type->typename, - sensor->temp_offset); - - if(sensor->type->interface == &SINGLE_WIRE) { - stream_write_format( - app->file_stream, "%d\n", unitemp_singlewire_sensorGetGPIO(sensor)->num); - } - if(sensor->type->interface == &SPI) { - uint8_t gpio_num = ((SPISensor*)sensor->instance)->CS_pin->num; - stream_write_format(app->file_stream, "%d\n", gpio_num); - } - - if(sensor->type->interface == &I2C) { - stream_write_format( - app->file_stream, "%X\n", ((I2CSensor*)sensor->instance)->currentI2CAdr); - } - if(sensor->type->interface == &ONE_WIRE) { - stream_write_format( - app->file_stream, - "%d %02X%02X%02X%02X%02X%02X%02X%02X\n", - ((OneWireSensor*)sensor->instance)->bus->gpio->num, - ((OneWireSensor*)sensor->instance)->deviceID[0], - ((OneWireSensor*)sensor->instance)->deviceID[1], - ((OneWireSensor*)sensor->instance)->deviceID[2], - ((OneWireSensor*)sensor->instance)->deviceID[3], - ((OneWireSensor*)sensor->instance)->deviceID[4], - ((OneWireSensor*)sensor->instance)->deviceID[5], - ((OneWireSensor*)sensor->instance)->deviceID[6], - ((OneWireSensor*)sensor->instance)->deviceID[7]); - } - } - - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Sensors have been successfully saved"); - return true; -} -void unitemp_sensors_reload(void) { - unitemp_sensors_deInit(); - unitemp_sensors_free(); - - unitemp_sensors_load(); - unitemp_sensors_init(); -} - -bool unitemp_sensor_isContains(Sensor* sensor) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(app->sensors[i] == sensor) return true; - } - return false; -} - -Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args) { - if(name == NULL || type == NULL) return NULL; - bool status = false; - //Выделение памяти под датчик - Sensor* sensor = malloc(sizeof(Sensor)); - if(sensor == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s allocation error", name); - return false; - } - - //Выделение памяти под имя - sensor->name = malloc(11); - if(sensor->name == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s name allocation error", name); - return false; - } - //Запись имени датчка - strcpy(sensor->name, name); - //Тип датчика - sensor->type = type; - //Статус датчика по умолчанию - ошибка - sensor->status = UT_SENSORSTATUS_ERROR; - //Время последнего опроса - sensor->lastPollingTime = - furi_get_tick() - 10000; //чтобы первый опрос произошёл как можно раньше - - sensor->temp = -128.0f; - sensor->hum = -128.0f; - sensor->pressure = -128.0f; - sensor->temp_offset = 0; - //Выделение памяти под инстанс датчика в зависимости от его интерфейса - status = sensor->type->interface->allocator(sensor, args); - - //Выход если датчик успешно развёрнут - if(status) { - UNITEMP_DEBUG("Sensor %s allocated", name); - return sensor; - } - //Выход с очисткой если память для датчика не была выделена - free(sensor->name); - free(sensor); - FURI_LOG_E(APP_NAME, "Sensor %s(%s) allocation error", name, type->typename); - return NULL; -} - -void unitemp_sensor_free(Sensor* sensor) { - if(sensor == NULL) { - FURI_LOG_E(APP_NAME, "Null pointer sensor releasing"); - return; - } - if(sensor->type == NULL) { - FURI_LOG_E(APP_NAME, "Sensor type is null"); - return; - } - if(sensor->type->mem_releaser == NULL) { - FURI_LOG_E(APP_NAME, "Sensor releaser is null"); - return; - } - bool status = false; - //Высвобождение памяти под инстанс - status = sensor->type->interface->mem_releaser(sensor); - - if(status) { - UNITEMP_DEBUG("Sensor %s memory successfully released", sensor->name); - } else { - FURI_LOG_E(APP_NAME, "Sensor %s memory is not released", sensor->name); - } - free(sensor->name); -} - -void unitemp_sensors_free(void) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - unitemp_sensor_free(app->sensors[i]); - } - app->sensors_count = 0; -} - -bool unitemp_sensors_init(void) { - bool result = true; - - //Перебор датчиков из списка - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - //Включение 5V если на порту 1 FZ его нет - //Может пропасть при отключении USB - if(furi_hal_power_is_otg_enabled() != true) { - furi_hal_power_enable_otg(); - UNITEMP_DEBUG("OTG enabled"); - } - if(!(*app->sensors[i]->type->initializer)(app->sensors[i])) { - FURI_LOG_E( - APP_NAME, - "An error occurred during sensor initialization %s", - app->sensors[i]->name); - result = false; - } - FURI_LOG_I(APP_NAME, "Sensor %s successfully initialized", app->sensors[i]->name); - } - app->sensors_ready = true; - return result; -} - -bool unitemp_sensors_deInit(void) { - bool result = true; - //Выключение 5 В если до этого оно не было включено - if(app->settings.lastOTGState != true) { - furi_hal_power_disable_otg(); - UNITEMP_DEBUG("OTG disabled"); - } - - //Перебор датчиков из списка - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(!(*app->sensors[i]->type->deinitializer)(app->sensors[i])) { - FURI_LOG_E( - APP_NAME, - "An error occurred during sensor deinitialization %s", - app->sensors[i]->name); - result = false; - } - } - return result; -} - -UnitempStatus unitemp_sensor_updateData(Sensor* sensor) { - if(sensor == NULL) return UT_SENSORSTATUS_ERROR; - - //Проверка на допустимость опроса датчика - if(furi_get_tick() - sensor->lastPollingTime < sensor->type->pollingInterval) { - //Возврат ошибки если последний опрос датчика был неудачным - if(sensor->status == UT_SENSORSTATUS_TIMEOUT) { - return UT_SENSORSTATUS_TIMEOUT; - } - return UT_SENSORSTATUS_EARLYPOOL; - } - - sensor->lastPollingTime = furi_get_tick(); - - if(!furi_hal_power_is_otg_enabled()) { - furi_hal_power_enable_otg(); - } - - sensor->status = sensor->type->interface->updater(sensor); - - if(sensor->status != UT_SENSORSTATUS_OK && sensor->status != UT_SENSORSTATUS_POLLING) { - UNITEMP_DEBUG("Sensor %s update status %d", sensor->name, sensor->status); - } - - if(sensor->status == UT_SENSORSTATUS_OK) { - if(app->settings.heat_index && - ((sensor->type->datatype & (UT_TEMPERATURE | UT_HUMIDITY)) == - (UT_TEMPERATURE | UT_HUMIDITY))) { - unitemp_calculate_heat_index(sensor); - } - if(app->settings.temp_unit == UT_TEMP_FAHRENHEIT) { - uintemp_celsiumToFarengate(sensor); - } - - sensor->temp += sensor->temp_offset / 10.f; - if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) { - unitemp_pascalToMmHg(sensor); - } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) { - unitemp_pascalToInHg(sensor); - } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) { - unitemp_pascalToKPa(sensor); - } - } - return sensor->status; -} - -void unitemp_sensors_updateValues(void) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - unitemp_sensor_updateData(unitemp_sensor_getActive(i)); - } -} diff --git a/applications/external/unitemp/Sensors.h b/applications/external/unitemp/Sensors.h deleted file mode 100644 index 339a4deff..000000000 --- a/applications/external/unitemp/Sensors.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SENSORS -#define UNITEMP_SENSORS -#include -#include - -//Маски бит для определения типов возвращаемых значений -#define UT_TEMPERATURE 0b00000001 -#define UT_HUMIDITY 0b00000010 -#define UT_PRESSURE 0b00000100 -#define UT_CO2 0b00001000 - -//Статусы опроса датчика -typedef enum { - UT_DATA_TYPE_TEMP = UT_TEMPERATURE, - UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY, - UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE, - UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - UT_DATA_TYPE_TEMP_HUM_CO2 = UT_TEMPERATURE | UT_HUMIDITY | UT_CO2, -} SensorDataType; - -//Типы возвращаемых данных -typedef enum { - UT_SENSORSTATUS_OK, //Всё хорошо, опрос успешен - UT_SENSORSTATUS_TIMEOUT, //Датчик не отозвался - UT_SENSORSTATUS_EARLYPOOL, //Опрос раньше положенной задержки - UT_SENSORSTATUS_BADCRC, //Неверная контрольная сумма - UT_SENSORSTATUS_ERROR, //Прочие ошибки - UT_SENSORSTATUS_POLLING, //В датчике происходит преобразование - UT_SENSORSTATUS_INACTIVE, //Датчик на редактировании или удалён - -} UnitempStatus; - -//Порт ввода/вывода Flipper Zero -typedef struct GPIO { - const uint8_t num; - const char* name; - const GpioPin* pin; -} GPIO; - -typedef struct Sensor Sensor; - -/** - * @brief Указатель функции выделения памяти и подготовки экземпляра датчика - */ -typedef bool(SensorAllocator)(Sensor* sensor, char* args); -/** - * @brief Указатель на функцию высвобождении памяти датчика - */ -typedef bool(SensorFree)(Sensor* sensor); -/** - * @brief Указатель функции инициализации датчика - */ -typedef bool(SensorInitializer)(Sensor* sensor); -/** - * @brief Указатель функции деинициализации датчика - */ -typedef bool(SensorDeinitializer)(Sensor* sensor); -/** - * @brief Указатель функции обновления значения датчика - */ -typedef UnitempStatus(SensorUpdater)(Sensor* sensor); - -//Типы подключения датчиков -typedef struct Interface { - //Имя интерфейса - const char* name; - //Функция выделения памяти интерфейса - SensorAllocator* allocator; - //Функция высвыбождения памяти интерфейса - SensorFree* mem_releaser; - //Функция обновления значения датчика по интерфейсу - SensorUpdater* updater; -} Interface; - -//Типы датчиков -typedef struct { - //Модель датчика - const char* typename; - //Полное имя с аналогами - const char* altname; - //Тип возвращаемых данных - SensorDataType datatype; - //Интерфейс подключения - const Interface* interface; - //Интервал опроса датчика - uint16_t pollingInterval; - //Функция выделения памяти для датчика - SensorAllocator* allocator; - //Функция высвыбождения памяти для датчика - SensorFree* mem_releaser; - //Функция инициализации датчика - SensorInitializer* initializer; - //Функция деинициализация датчика - SensorDeinitializer* deinitializer; - //Функция обновления значения датчка - SensorUpdater* updater; -} SensorType; - -//Датчик -typedef struct Sensor { - //Имя датчика - char* name; - //Температура - float temp; - float heat_index; - //Относительная влажность - float hum; - //Атмосферное давление - float pressure; - // Концентрация CO2 - float co2; - //Тип датчика - const SensorType* type; - //Статус последнего опроса датчика - UnitempStatus status; - //Время последнего опроса датчика - uint32_t lastPollingTime; - //Смещение по температуре (x10) - int8_t temp_offset; - //Экземпляр датчика - void* instance; -} Sensor; - -extern const Interface SINGLE_WIRE; //Собственный однопроводной протокол датчиков DHTXX и AM23XX -extern const Interface ONE_WIRE; //Однопроводной протокол Dallas -extern const Interface I2C; //I2C_2 (PC0, PC1) -extern const Interface SPI; //SPI_1 (MOSI - 2, MISO - 3, CS - 4, SCK - 5) - -/* ============================= Датчик(и) ============================= */ -/** - * @brief Выделение памяти под датчик - * - * @param name Имя датчика - * @param type Тип датчика - * @param args Указатель на строку с парамерами датчика - * @return Указатель на датчик в случае успешного выделения памяти, NULL при ошибке - */ -Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args); - -/** - * @brief Высвыбождение памяти конкретного датчка - * @param sensor Указатель на датчик - */ -void unitemp_sensor_free(Sensor* sensor); - -/** - * @brief Обновление данных указанного датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_sensor_updateData(Sensor* sensor); - -/** - * @brief Проверка наличия датчика в памяти - * - * @param sensor Указатель на датчик - * @return Истина если этот датчик уже загружен, ложь если это новый датчик - */ -bool unitemp_sensor_isContains(Sensor* sensor); - -/** - * @brief Получить датчик из списка по индексу - * - * @param index Индекс датчика (0 - unitemp_sensors_getCount()) - * @return Указатель на датчик при успехе, NULL при неудаче - */ -Sensor* unitemp_sensor_getActive(uint8_t index); - -/** - * @brief Загрузка датчиков с SD-карты - * @return Истина если загрузка прошла успешно - */ -bool unitemp_sensors_load(); - -/** - * @brief Функция перезагрузки датчиков с SD-карты -*/ -void unitemp_sensors_reload(void); - -/** - * @brief Сохранение датчиков на SD-карту - * @return Истина если сохранение прошло успешно - */ -bool unitemp_sensors_save(void); - -/** - * @brief Удаление датчика - * - * @param sensor Указатель на датчик - */ -void unitemp_sensor_delete(Sensor* sensor); - -/** - * @brief Инициализация загруженных датчиков - * @return Истина если всё прошло успешно - */ -bool unitemp_sensors_init(void); - -/** - * @brief Деинициализация загруженных датчиков - * @return Истина если всё прошло успешно - */ -bool unitemp_sensors_deInit(void); - -/** - * @brief Высвыбождение памяти всех датчиков - */ -void unitemp_sensors_free(void); - -/** - * @brief Обновить данные всех датчиков - */ -void unitemp_sensors_updateValues(void); - -/** - * @brief Получить количество загруженных датчиков - * @return Количество датчиков - */ -uint8_t unitemp_sensors_getCount(void); - -/** - * @brief Добавить датчик в общий список - * @param sensor Указатель на датчик - */ -void unitemp_sensors_add(Sensor* sensor); - -/** -* @brief Получить списк доступных типов датчиков -* @return Указатель на список датчиков -*/ -const SensorType** unitemp_sensors_getTypes(void); - -/** -* @brief Получить количество доступных типов датчиков -* @return Количество доступных типов датчиков -*/ -uint8_t unitemp_sensors_getTypesCount(void); - -/** - * @brief Получить тип сенсора по его индексу - * @param index Индекс типа датчика (от 0 до SENSOR_TYPES_COUNT) - * @return const SensorType* - */ -const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index); - -/** - * @brief Преобразовать строчное название датчка в указатель - * - * @param str Имя датчика в виде строки - * @return Указатель на тип датчика при успехе, иначе NULL - */ -const SensorType* unitemp_sensors_getTypeFromStr(char* str); - -/** - * @brief Получить количество активных датчиков - * - * @return Количество активных датчиков - */ -uint8_t unitemp_sensors_getActiveCount(void); - -/* ============================= GPIO ============================= */ -/** - * @brief Конвертация номера порта на корпусе FZ в GPIO - * @param name Номер порта на корпусе FZ - * @return Указатель на GPIO при успехе, NULL при ошибке - */ -const GPIO* unitemp_gpio_getFromInt(uint8_t name); -/** - * @brief Конвертация GPIO в номер на корпусе FZ - * @param gpio Указатель на порт - * @return Номер порта на корпусе FZ - */ -uint8_t unitemp_gpio_toInt(const GPIO* gpio); - -/** - * @brief Блокировка GPIO указанным интерфейсом - * @param gpio Указатель на порт - * @param interface Указатель на интерфейс, которым порт будет занят - */ -void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface); - -/** - * @brief Разблокировка порта - * @param gpio Указатель на порт - */ -void unitemp_gpio_unlock(const GPIO* gpio); -/** - * @brief Получить количество доступных портов для указанного интерфейса - * @param interface Указатель на интерфейс - * @return Количество доступных портов - */ -uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport); -/** - * @brief Получить указатель на доступный для интерфейса порт по индексу - * @param interface Указатель на интерфейс - * @param index Номер порта (от 0 до unitemp_gpio_getAviablePortsCount()) - * @param extraport Указатель на дополнительный порт, который будет принудительно считаться доступным. Можно указать NULL если не требуется - * @return Указатель на доступный порт - */ -const GPIO* - unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport); - -/* Датчики */ -//DHTxx и их производные -#include "./interfaces/SingleWireSensor.h" -//DS18x2x -#include "./interfaces/OneWireSensor.h" -#include "./sensors/LM75.h" -//BMP280, BME280, BME680 -#include "./sensors/BMx280.h" -#include "./sensors/BME680.h" -#include "./sensors/AM2320.h" -#include "./sensors/DHT20.h" -#include "./sensors/SHT30.h" -#include "./sensors/BMP180.h" -#include "./sensors/HTU21x.h" -#include "./sensors/HDC1080.h" -#include "./sensors/MAX31855.h" -#include "./sensors/MAX6675.h" -#include "./sensors/SCD30.h" -#include "./sensors/SCD40.h" -#endif diff --git a/applications/external/unitemp/application.fam b/applications/external/unitemp/application.fam deleted file mode 100644 index b3f9dec35..000000000 --- a/applications/external/unitemp/application.fam +++ /dev/null @@ -1,17 +0,0 @@ -App( - appid="unitemp", - name="[GPIO] Unitemp", - apptype=FlipperAppType.EXTERNAL, - entry_point="unitemp_app", - requires=[ - "gui", - ], - stack_size=2 * 1024, - fap_description="Universal temperature sensors reader", - fap_version="1.4", - fap_author="@quen0n & (fixes by @xMasterX)", - fap_weburl="https://github.com/quen0n/unitemp-flipperzero", - fap_category="GPIO", - fap_icon="icon.png", - fap_icon_assets="assets", -) diff --git a/applications/external/unitemp/assets/co2_11x14.png b/applications/external/unitemp/assets/co2_11x14.png deleted file mode 100644 index 2a2b5e068..000000000 Binary files a/applications/external/unitemp/assets/co2_11x14.png and /dev/null differ diff --git a/applications/external/unitemp/assets/flipper_happy_2_60x38.png b/applications/external/unitemp/assets/flipper_happy_2_60x38.png deleted file mode 100644 index c4322c237..000000000 Binary files a/applications/external/unitemp/assets/flipper_happy_2_60x38.png and /dev/null differ diff --git a/applications/external/unitemp/assets/flipper_happy_60x38.png b/applications/external/unitemp/assets/flipper_happy_60x38.png deleted file mode 100644 index db57e12c2..000000000 Binary files a/applications/external/unitemp/assets/flipper_happy_60x38.png and /dev/null differ diff --git a/applications/external/unitemp/assets/flipper_sad_60x38.png b/applications/external/unitemp/assets/flipper_sad_60x38.png deleted file mode 100644 index 994cf4bde..000000000 Binary files a/applications/external/unitemp/assets/flipper_sad_60x38.png and /dev/null differ diff --git a/applications/external/unitemp/assets/heat_index_11x14.png b/applications/external/unitemp/assets/heat_index_11x14.png deleted file mode 100644 index f2f0d4ce5..000000000 Binary files a/applications/external/unitemp/assets/heat_index_11x14.png and /dev/null differ diff --git a/applications/external/unitemp/assets/hum_9x15.png b/applications/external/unitemp/assets/hum_9x15.png deleted file mode 100644 index 70cedb8f5..000000000 Binary files a/applications/external/unitemp/assets/hum_9x15.png and /dev/null differ diff --git a/applications/external/unitemp/assets/in_hg_15x15.png b/applications/external/unitemp/assets/in_hg_15x15.png deleted file mode 100644 index a27782482..000000000 Binary files a/applications/external/unitemp/assets/in_hg_15x15.png and /dev/null differ diff --git a/applications/external/unitemp/assets/mm_hg_15x15.png b/applications/external/unitemp/assets/mm_hg_15x15.png deleted file mode 100644 index 66b5dc6ea..000000000 Binary files a/applications/external/unitemp/assets/mm_hg_15x15.png and /dev/null differ diff --git a/applications/external/unitemp/assets/pressure_7x13.png b/applications/external/unitemp/assets/pressure_7x13.png deleted file mode 100644 index 43aaa7bbc..000000000 Binary files a/applications/external/unitemp/assets/pressure_7x13.png and /dev/null differ diff --git a/applications/external/unitemp/assets/repo_qr_50x50.png b/applications/external/unitemp/assets/repo_qr_50x50.png deleted file mode 100644 index 5bf668497..000000000 Binary files a/applications/external/unitemp/assets/repo_qr_50x50.png and /dev/null differ diff --git a/applications/external/unitemp/assets/sherlok_53x45.png b/applications/external/unitemp/assets/sherlok_53x45.png deleted file mode 100644 index 1f258737e..000000000 Binary files a/applications/external/unitemp/assets/sherlok_53x45.png and /dev/null differ diff --git a/applications/external/unitemp/assets/temp_C_11x14.png b/applications/external/unitemp/assets/temp_C_11x14.png deleted file mode 100644 index 19cf423b4..000000000 Binary files a/applications/external/unitemp/assets/temp_C_11x14.png and /dev/null differ diff --git a/applications/external/unitemp/assets/temp_F_11x14.png b/applications/external/unitemp/assets/temp_F_11x14.png deleted file mode 100644 index 5ed469337..000000000 Binary files a/applications/external/unitemp/assets/temp_F_11x14.png and /dev/null differ diff --git a/applications/external/unitemp/icon.png b/applications/external/unitemp/icon.png deleted file mode 100644 index f0958ecdc..000000000 Binary files a/applications/external/unitemp/icon.png and /dev/null differ diff --git a/applications/external/unitemp/interfaces/I2CSensor.c b/applications/external/unitemp/interfaces/I2CSensor.c deleted file mode 100644 index e5901c282..000000000 --- a/applications/external/unitemp/interfaces/I2CSensor.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "I2CSensor.h" - -static uint8_t sensors_count = 0; - -void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle) { - furi_hal_i2c_acquire(handle); - LL_GPIO_SetPinPull(gpio_ext_pc1.port, gpio_ext_pc1.pin, LL_GPIO_PULL_UP); - LL_GPIO_SetPinPull(gpio_ext_pc0.port, gpio_ext_pc0.pin, LL_GPIO_PULL_UP); -} - -bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_is_device_ready(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - uint8_t buff[1] = {0}; - furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return buff[0]; -} - -bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_rx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = - furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - uint8_t buff[1] = {value}; - bool status = - furi_hal_i2c_write_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_tx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_write_mem( - i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args) { - bool status = false; - I2CSensor* instance = malloc(sizeof(I2CSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - instance->i2c = &furi_hal_i2c_handle_external; - sensor->instance = instance; - - //Указание функций инициализации, деинициализации и обновления данных, а так же адреса на шине I2C - status = sensor->type->allocator(sensor, args); - int i2c_addr; - sscanf(args, "%X", &i2c_addr); - - //Установка адреса шины I2C - if(i2c_addr >= instance->minI2CAdr && i2c_addr <= instance->maxI2CAdr) { - instance->currentI2CAdr = i2c_addr; - } else { - instance->currentI2CAdr = instance->minI2CAdr; - } - - //Блокировка портов GPIO - sensors_count++; - unitemp_gpio_lock(unitemp_gpio_getFromInt(15), &I2C); - unitemp_gpio_lock(unitemp_gpio_getFromInt(16), &I2C); - - return status; -} - -bool unitemp_I2C_sensor_free(Sensor* sensor) { - bool status = sensor->type->mem_releaser(sensor); - free(sensor->instance); - if(--sensors_count == 0) { - unitemp_gpio_unlock(unitemp_gpio_getFromInt(15)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(16)); - } - - return status; -} - -UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor) { - if(sensor->status != UT_SENSORSTATUS_OK) { - sensor->type->initializer(sensor); - } - return sensor->type->updater(sensor); -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/I2CSensor.h b/applications/external/unitemp/interfaces/I2CSensor.h deleted file mode 100644 index 4d468aae1..000000000 --- a/applications/external/unitemp/interfaces/I2CSensor.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_I2C -#define UNITEMP_I2C - -#include "../unitemp.h" - -#include - -//Структура I2C датчика -typedef struct I2CSensor { - //Указатель на интерфейс I2C - FuriHalI2cBusHandle* i2c; - //Минимальный адрес устройства на шине I2C - uint8_t minI2CAdr; - //Максимальный адрес устройства на шине I2C - uint8_t maxI2CAdr; - //Текущий адрес устройства на шине I2C - uint8_t currentI2CAdr; - //Указатель на собственный экземпляр датчика - void* sensorInstance; -} I2CSensor; - -/** - * @brief Заблокировать шину I2C - * - * @param handle Указатель на шину - */ -void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle); - -/** - * @brief Проверить наличие датчика на шине - * - * @param i2c_sensor Указатель на датчик - * @return Истина если устройство отозвалось - */ -bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor); - -/** - * @brief Выделение памяти для датчика на шине I2C - * @param sensor Указатель на датчик - * @param st Тип датчика - * @return Истина если всё ок - */ -bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_I2C_sensor_free(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor); -/** - * @brief Прочитать значение регистра reg - * @param i2c_sensor Указатель на инстанс датчика - * @param reg Номер регистра - * @return Значение регистра - */ -uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg); - -/** - * @brief Прочитать масссив значений из памяти - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся чтение - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив куда будут считаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data); - -/** - * @brief Записать значение в регистр - * @param i2c_sensor Указатель на инстанс датчика - * @param reg Номер регистра - * @param value Значение для записи - * @return Истина если значение записано - */ -bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value); - -/** - * @brief Записать масссив значений в память - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся запись - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив откуда будут записаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data); - -/** - * @brief Прочитать массив данных по шине I2C - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся чтение - * @param data Указатель на массив куда будут считаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data); - -/** - * @brief Записать масссив данных по шине I2C - * @param i2c_sensor Указатель на инстанс датчика - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив откуда будут записаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/OneWireSensor.c b/applications/external/unitemp/interfaces/OneWireSensor.c deleted file mode 100644 index 377eb0d08..000000000 --- a/applications/external/unitemp/interfaces/OneWireSensor.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -//Использован код Дмитрия Погребняка: https://aterlux.ru/article/1wire - -#include "OneWireSensor.h" -#include -#include - -const SensorType Dallas = { - .typename = "Dallas", - .altname = "Dallas (DS18x2x)", - .interface = &ONE_WIRE, - .datatype = UT_DATA_TYPE_TEMP, - .pollingInterval = 1000, - .allocator = unitemp_onewire_sensor_alloc, - .mem_releaser = unitemp_onewire_sensor_free, - .initializer = unitemp_onewire_sensor_init, - .deinitializer = unitemp_onewire_sensor_deinit, - .updater = unitemp_onewire_sensor_update}; - -// Переменные для хранения промежуточного результата сканирования шины -// найденный восьмибайтовый адрес -static uint8_t onewire_enum[8] = {0}; - -OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio) { - if(gpio == NULL) { - return NULL; - } - - //Проверка на наличие шины на этом порте - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE && - ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus->gpio->num == gpio->num) { - //Если шина на этом порту уже есть, то возврат указателя на шину - return ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus; - } - } - - OneWireBus* bus = malloc(sizeof(OneWireBus)); - - bus->device_count = 0; - bus->gpio = gpio; - bus->powerMode = PWR_PASSIVE; - - UNITEMP_DEBUG("one wire bus (port %d) allocated", gpio->num); - - return bus; -} - -bool unitemp_onewire_bus_init(OneWireBus* bus) { - if(bus == NULL) return false; - bus->device_count++; - //Выход если шина уже была инициализирована - if(bus->device_count > 1) return true; - - bus->host = onewire_host_alloc(bus->gpio->pin); - - unitemp_gpio_lock(bus->gpio, &ONE_WIRE); - //Высокий уровень по умолчанию - furi_hal_gpio_write(bus->gpio->pin, true); - //Режим работы - OpenDrain, подтяжка включается на всякий случай - furi_hal_gpio_init( - bus->gpio->pin, //Порт FZ - GpioModeOutputOpenDrain, //Режим работы - открытый сток - GpioPullUp, //Принудительная подтяжка линии данных к питанию - GpioSpeedVeryHigh); //Скорость работы - максимальная - - return true; -} - -bool unitemp_onewire_bus_deinit(OneWireBus* bus) { - UNITEMP_DEBUG("devices on wire %d: %d", bus->gpio->num, bus->device_count); - bus->device_count--; - if(bus->device_count <= 0) { - bus->device_count = 0; - unitemp_gpio_unlock(bus->gpio); - //Режим работы - аналог, подтяжка выключена - furi_hal_gpio_init( - bus->gpio->pin, //Порт FZ - GpioModeAnalog, //Режим работы - аналог - GpioPullNo, //Подтяжка выключена - GpioSpeedLow); //Скорость работы - минимальная - //Низкий уровень по умолчанию - furi_hal_gpio_write(bus->gpio->pin, false); - return true; - } else { - return false; - } -} -inline bool unitemp_onewire_bus_start(OneWireBus* bus) { - return onewire_host_reset(bus->host); -} - -inline void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state) { - onewire_host_write_bit(bus->host, state); -} - -inline void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data) { - onewire_host_write(bus->host, data); -} - -void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) { - for(uint8_t i = 0; i < len; i++) { - onewire_host_write(bus->host, data[i]); - } -} - -inline bool unitemp_onewire_bus_read_bit(OneWireBus* bus) { - return onewire_host_read_bit(bus->host); -} - -inline uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus) { - return onewire_host_read(bus->host); -} - -void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) { - onewire_host_read_bytes(bus->host, data, len); -} - -static uint8_t onewire_CRC_update(uint8_t crc, uint8_t b) { - for(uint8_t p = 8; p; p--) { - crc = ((crc ^ b) & 1) ? (crc >> 1) ^ 0b10001100 : (crc >> 1); - b >>= 1; - } - return crc; -} - -bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len) { - uint8_t crc = 0; - for(uint8_t i = 0; i < len; i++) { - crc = onewire_CRC_update(crc, data[i]); - } - return !crc; -} - -char* unitemp_onewire_sensor_getModel(Sensor* sensor) { - OneWireSensor* ow_sensor = sensor->instance; - switch(ow_sensor->deviceID[0]) { - case FC_DS18B20: - return "DS18B20"; - case FC_DS18S20: - return "DS18S20"; - case FC_DS1822: - return "DS1822"; - default: - return "unknown"; - } -} - -bool unitemp_onewire_sensor_readID(OneWireSensor* instance) { - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_send_byte(instance->bus, 0x33); // Чтение ПЗУ - unitemp_onewire_bus_read_byteArray(instance->bus, instance->deviceID, 8); - if(!unitemp_onewire_CRC_check(instance->deviceID, 8)) { - memset(instance->deviceID, 0, 8); - return false; - } - instance->familyCode = instance->deviceID[0]; - return true; -} - -void unitemp_onewire_bus_enum_init(OneWireBus* bus) { - onewire_host_reset_search(bus->host); -} - -uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus) { - if(onewire_host_search(bus->host, onewire_enum, OneWireHostSearchModeNormal)) { - return onewire_enum; - } else { - return NULL; - } -} - -void unitemp_onewire_bus_select_sensor(OneWireSensor* instance) { - unitemp_onewire_bus_send_byte(instance->bus, 0x55); - unitemp_onewire_bus_send_byteArray(instance->bus, instance->deviceID, 8); -} - -bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args) { - OneWireSensor* instance = malloc(sizeof(OneWireSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - //Очистка адреса - memset(instance->deviceID, 0, 8); - - int gpio, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7; - sscanf( - args, - "%d %2X%2X%2X%2X%2X%2X%2X%2X", - &gpio, - &addr_0, - &addr_1, - &addr_2, - &addr_3, - &addr_4, - &addr_5, - &addr_6, - &addr_7); - instance->deviceID[0] = addr_0; - instance->deviceID[1] = addr_1; - instance->deviceID[2] = addr_2; - instance->deviceID[3] = addr_3; - instance->deviceID[4] = addr_4; - instance->deviceID[5] = addr_5; - instance->deviceID[6] = addr_6; - instance->deviceID[7] = addr_7; - - instance->familyCode = instance->deviceID[0]; - - instance->bus = uintemp_onewire_bus_alloc(unitemp_gpio_getFromInt(gpio)); - - if(instance != NULL) { - return true; - } - FURI_LOG_E(APP_NAME, "Sensor %s bus allocation error", sensor->name); - free(instance); - return false; -} - -bool unitemp_onewire_sensor_free(Sensor* sensor) { - if(((OneWireSensor*)sensor->instance)->bus != NULL) { - if(((OneWireSensor*)sensor->instance)->bus->device_count == 0) { - free(((OneWireSensor*)sensor->instance)->bus); - } - } - - free(sensor->instance); - - return true; -} - -bool unitemp_onewire_sensor_init(Sensor* sensor) { - OneWireSensor* instance = sensor->instance; - if(instance == NULL || instance->bus == NULL) { - FURI_LOG_E(APP_NAME, "Sensor pointer is null!"); - return false; - } - - unitemp_onewire_bus_init(instance->bus); - - if(instance->familyCode == FC_DS18B20 || instance->familyCode == FC_DS1822) { - //Установка разрядности в 10 бит - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0x4E); // Запись в память - uint8_t buff[3]; - //Значения тревоги - buff[0] = 0x4B; //Значение нижнего предела температуры - buff[1] = 0x46; //Значение верхнего предела температуры - //Конфигурация - buff[2] = 0b01111111; //12 бит разрядность преобразования - unitemp_onewire_bus_send_byteArray(instance->bus, buff, 3); - - //Сохранение значений в EEPROM для автоматического восстановления после сбоев питания - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0x48); // Запись в EEPROM - } - - return true; -} - -bool unitemp_onewire_sensor_deinit(Sensor* sensor) { - OneWireSensor* instance = sensor->instance; - if(instance == NULL || instance->bus == NULL) return false; - unitemp_onewire_bus_deinit(instance->bus); - - return true; -} - -UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor) { - //Снятие особого статуса с датчика при пассивном режиме питания - if(sensor->status == UT_SENSORSTATUS_EARLYPOOL) { - return UT_SENSORSTATUS_POLLING; - } - - OneWireSensor* instance = sensor->instance; - uint8_t buff[9] = {0}; - if(sensor->status != UT_SENSORSTATUS_POLLING) { - //Если датчик в прошлый раз не отозвался, проверка его наличия на шине - if(sensor->status == UT_SENSORSTATUS_TIMEOUT || sensor->status == UT_SENSORSTATUS_BADCRC) { - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad - unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); - if(!unitemp_onewire_CRC_check(buff, 9)) { - UNITEMP_DEBUG("Sensor %s is not found", sensor->name); - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - //Запуск преобразования на всех датчиках в режиме пассивного питания - if(instance->bus->powerMode == PWR_PASSIVE) { - unitemp_onewire_bus_send_byte(instance->bus, 0xCC); // skip addr - //Установка на всех датчиках этой шины особого статуса, чтобы не запускать преобразование ещё раз - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE && - ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus == instance->bus) { - unitemp_sensor_getActive(i)->status = UT_SENSORSTATUS_EARLYPOOL; - } - } - - } else { - unitemp_onewire_bus_select_sensor(instance); - } - - unitemp_onewire_bus_send_byte(instance->bus, 0x44); // convert t - if(instance->bus->powerMode == PWR_PASSIVE) { - furi_hal_gpio_write(instance->bus->gpio->pin, true); - furi_hal_gpio_init( - instance->bus->gpio->pin, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); - } - return UT_SENSORSTATUS_POLLING; - } else { - if(instance->bus->powerMode == PWR_PASSIVE) { - furi_hal_gpio_write(instance->bus->gpio->pin, true); - furi_hal_gpio_init( - instance->bus->gpio->pin, GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); - } - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad - unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); - if(!unitemp_onewire_CRC_check(buff, 9)) { - UNITEMP_DEBUG("Failed CRC check: %s", sensor->name); - return UT_SENSORSTATUS_BADCRC; - } - int16_t raw = buff[0] | ((int16_t)buff[1] << 8); - if(instance->familyCode == FC_DS18S20) { - //Песевдо-12-бит. Отключено из-за неестественности и нестабильности показаний по сравнению с DS18B20 - //sensor->temp = ((float)raw / 2.0f) - 0.25f + (16.0f - buff[6]) / 16.0f; - //Честные 9 бит - sensor->temp = ((float)raw / 2.0f); - } else { - sensor->temp = (float)raw / 16.0f; - } - } - - return UT_SENSORSTATUS_OK; -} - -bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2) { - if(id1 == NULL || id2 == NULL) return false; - for(uint8_t i = 0; i < 8; i++) { - if(id1[i] != id2[i]) return false; - } - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/OneWireSensor.h b/applications/external/unitemp/interfaces/OneWireSensor.h deleted file mode 100644 index cb031d161..000000000 --- a/applications/external/unitemp/interfaces/OneWireSensor.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_OneWire -#define UNITEMP_OneWire - -#include "../unitemp.h" -#include - -//Коды семейства устройств -typedef enum DallasFamilyCode { - FC_DS18S20 = 0x10, - FC_DS1822 = 0x22, - FC_DS18B20 = 0x28, -} DallasFamilyCode; - -//Режим питания датчка -typedef enum PowerMode { - PWR_PASSIVE, //Питание от линии данных - PWR_ACTIVE //Питание от источника питания -} PowerMode; - -//Инстанс шины one wire -typedef struct { - //Порт подключения датчика - const GPIO* gpio; - //Количество устройств на шине - //Обновляется при ручном добавлении датчика на эту шину - int8_t device_count; - //Режим питания датчиков на шине - PowerMode powerMode; - - OneWireHost* host; -} OneWireBus; - -//Инстанс датчика one wire -typedef struct OneWireSensor { - //Указатель на шину OneWire - OneWireBus* bus; - //Текущий адрес устройства на шине OneWire - uint8_t deviceID[8]; - //Код семейства устройств - DallasFamilyCode familyCode; -} OneWireSensor; - -/** - * @brief Выделение памяти для датчика на шине OneWire - * @param sensor Указатель на датчик - * @param args Указатель на массив аргументов с параметрами датчика - * @return Истина если всё ок - */ -bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_onewire_sensor_free(Sensor* sensor); - -/** - * @brief Инициализации датчика на шине one wire - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_onewire_sensor_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_onewire_sensor_deinit(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor); - -/** - * @brief Выделение памяти для шины one wire и её инициализация - * @param gpio Порт на котором необходимо создать шину - * @return При успехе возвращает указатель на шину one wire - */ -OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio); - -/** - * @brief Инициализация шины one wire - * - * @param bus Указатель на шину - * @return Истина если инициализация успешна - */ -bool unitemp_onewire_bus_init(OneWireBus* bus); - -/** - * @brief Деинициализация шины one wire - * - * @param bus Указатель на шину - * @return Истина если шина была деинициализирована, ложь если на шине остались устройства - */ -bool unitemp_onewire_bus_deinit(OneWireBus* bus); - -/** - * @brief Запуск общения с датчиками на шине one wire - * @param bus Указатель на шину - * @return Истина если хотя бы одно устройство отозвалось - */ -bool unitemp_onewire_bus_start(OneWireBus* bus); - -/** - * @brief Отправить 1 бит данных на шину one wire - * @param bus Указатель на шину - * @param state Логический уровень - */ -void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state); - -/** - * @brief Запись байта на шину one wire - * - * @param bus Указатель на шину one wire - * @param data Записываемый байт - */ -void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data); - -/** - * @brief Запись массива байт на шину one wire - * - * @param bus Указатель на шину one wire - * @param data Указатель на массив, откуда будут записаны данные - * @param len Количество байт - */ -void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len); - -/** - * @brief Чтение бита на шине one wire - * - * @param bus Указатель на шину one wire - * @return Логический уровень бита - */ -bool unitemp_onewire_bus_read_bit(OneWireBus* bus); - -/** - * @brief Чтение байта с шины One Wire - * - * @param bus Указатель на шину one wire - * @return Байт информации - **/ -uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus); - -/** - * @brief Чтение массива байт с шины One Wire - * - * @param bus Указатель на шину one wire - * @param data Указатель на массив, куда будут записаны данные - * @param len Количество байт - */ -void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len); - -/** - * @brief Проверить контрольную сумму массива данных - * - * @param data Указатель на массив данных - * @param len Длина массива (включая байт CRC) - * @return Истина если контрольная сумма корректная - */ -bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len); - -/** - * @brief Получить имя модели датчика на шине One Wire - * - * @param sensor Указатель на датчик - * @return Указатель на строку с названием - */ -char* unitemp_onewire_sensor_getModel(Sensor* sensor); - -/** - * @brief Чтение индификатора единственного датчика. ID запишется в инстанс датчика - * - * @param instance Указатель на инстанс датчика - * @return Истина, если код успешно прочитан, ложь если устройство отсутствует или устройств на шине больше одного - */ -bool unitemp_oneWire_sensor_readID(OneWireSensor* instance); - -/** - * @brief Команда выбора определённого датчка по его ID - * @param instance Указатель на датчик one wire - */ -void unitemp_onewire_bus_select_sensor(OneWireSensor* instance); - -/** - * @brief Инициализация процесса поиска адресов на шине one wire - */ -void unitemp_onewire_bus_enum_init(OneWireBus* bus); - -/** - * @brief Перечисляет устройства на шине one wire и получает очередной адрес - * @param bus Указатель на шину one wire - * @return Возвращает указатель на буфер, содержащий восьмибайтовое значение адреса, либо NULL, если поиск завешён - */ -uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus); - -/** - * @brief Сравнить ID датчиков - * - * @param id1 Указатель на адрес первого датчика - * @param id2 Указатель на адрес второго датчика - * @return Истина если ID индентичны - */ -bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2); - -extern const SensorType Dallas; -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SPISensor.c b/applications/external/unitemp/interfaces/SPISensor.c deleted file mode 100644 index b53aed28d..000000000 --- a/applications/external/unitemp/interfaces/SPISensor.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include "SPISensor.h" - -static uint8_t sensors_count = 0; - -bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args) { - if(args == NULL) return false; - - //Создание инстанса датчика SPI - SPISensor* instance = malloc(sizeof(SPISensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - - //Определение GPIO chip select - int gpio = 255; - sscanf(args, "%d", &gpio); - instance->CS_pin = unitemp_gpio_getFromInt(gpio); - if(instance->CS_pin == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name); - free(instance); - return false; - } - - instance->spi = malloc(sizeof(FuriHalSpiBusHandle)); - memcpy(instance->spi, &furi_hal_spi_bus_handle_external, sizeof(FuriHalSpiBusHandle)); - - instance->spi->cs = instance->CS_pin->pin; - - bool status = sensor->type->allocator(sensor, args); - - //Блокировка портов GPIO - sensors_count++; - unitemp_gpio_lock(unitemp_gpio_getFromInt(2), &SPI); - unitemp_gpio_lock(unitemp_gpio_getFromInt(3), &SPI); - unitemp_gpio_lock(unitemp_gpio_getFromInt(5), &SPI); - unitemp_gpio_lock(instance->CS_pin, &SPI); - return status; -} - -bool unitemp_spi_sensor_free(Sensor* sensor) { - bool status = sensor->type->mem_releaser(sensor); - unitemp_gpio_unlock(((SPISensor*)sensor->instance)->CS_pin); - free(((SPISensor*)(sensor->instance))->spi); - free(sensor->instance); - - if(--sensors_count == 0) { - unitemp_gpio_unlock(unitemp_gpio_getFromInt(2)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(3)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(5)); - } - - return status; -} - -bool unitemp_spi_sensor_init(Sensor* sensor) { - return sensor->type->initializer(sensor); -} - -bool unitemp_spi_sensor_deinit(Sensor* sensor) { - UNUSED(sensor); - - return true; -} - -UnitempStatus unitemp_spi_sensor_update(Sensor* sensor) { - return sensor->type->updater(sensor); -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SPISensor.h b/applications/external/unitemp/interfaces/SPISensor.h deleted file mode 100644 index 40f284b04..000000000 --- a/applications/external/unitemp/interfaces/SPISensor.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SPI -#define UNITEMP_SPI - -#include "../unitemp.h" -#include - -//Структура SPI датчика -typedef struct SPISensor { - //Указатель на интерфейс SPI - FuriHalSpiBusHandle* spi; - //Порт подключения CS - const GPIO* CS_pin; -} SPISensor; - -/** - * @brief Выделение памяти для датчика с интерфейсом SPI - * @param sensor Указатель на датчик - * @param args Указатель на массив аргументов с параметрами датчика - * @return Истина если всё ок - */ -bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_spi_sensor_free(Sensor* sensor); - -/** - * @brief Инициализации датчика с интерфейсом one wire - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_spi_sensor_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_spi_sensor_deinit(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_spi_sensor_update(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SingleWireSensor.c b/applications/external/unitemp/interfaces/SingleWireSensor.c deleted file mode 100644 index d6d1b092b..000000000 --- a/applications/external/unitemp/interfaces/SingleWireSensor.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "SingleWireSensor.h" - -//Максимальное количество попугаев ожидания датчика -#define POLLING_TIMEOUT_TICKS 500 - -/* Типы датчиков и их параметры */ -const SensorType DHT11 = { - .typename = "DHT11", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT12_SW = { - .typename = "DHT12", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT21 = { - .typename = "DHT21", - .altname = "DHT21/AM2301", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 1000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT22 = { - .typename = "DHT22", - .altname = "DHT22/AM2302", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType AM2320_SW = { - .typename = "AM2320", - .altname = "AM2320 (single wire)", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; - -bool unitemp_singlewire_alloc(Sensor* sensor, char* args) { - if(args == NULL) return false; - SingleWireSensor* instance = malloc(sizeof(SingleWireSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - - int gpio = 255; - sscanf(args, "%d", &gpio); - - if(unitemp_singlewire_sensorSetGPIO(sensor, unitemp_gpio_getFromInt(gpio))) { - return true; - } - FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name); - free(instance); - return false; -} -bool unitemp_singlewire_free(Sensor* sensor) { - free(sensor->instance); - - return true; -} - -bool unitemp_singlewire_init(Sensor* sensor) { - SingleWireSensor* instance = ((Sensor*)sensor)->instance; - if(instance == NULL || instance->gpio == NULL) { - FURI_LOG_E(APP_NAME, "Sensor pointer is null!"); - return false; - } - unitemp_gpio_lock(instance->gpio, &SINGLE_WIRE); - //Высокий уровень по умолчанию - furi_hal_gpio_write(instance->gpio->pin, true); - //Режим работы - OpenDrain, подтяжка включается на всякий случай - furi_hal_gpio_init( - instance->gpio->pin, //Порт FZ - GpioModeOutputOpenDrain, //Режим работы - открытый сток - GpioPullUp, //Принудительная подтяжка линии данных к питанию - GpioSpeedVeryHigh); //Скорость работы - максимальная - return true; -} - -bool unitemp_singlewire_deinit(Sensor* sensor) { - SingleWireSensor* instance = ((Sensor*)sensor)->instance; - if(instance == NULL || instance->gpio == NULL) return false; - unitemp_gpio_unlock(instance->gpio); - //Низкий уровень по умолчанию - furi_hal_gpio_write(instance->gpio->pin, false); - //Режим работы - аналог, подтяжка выключена - furi_hal_gpio_init( - instance->gpio->pin, //Порт FZ - GpioModeAnalog, //Режим работы - аналог - GpioPullNo, //Подтяжка выключена - GpioSpeedLow); //Скорость работы - минимальная - return true; -} - -bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) { - if(sensor == NULL || gpio == NULL) return false; - SingleWireSensor* instance = sensor->instance; - instance->gpio = gpio; - return true; -} -const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor) { - if(sensor == NULL) return NULL; - SingleWireSensor* instance = sensor->instance; - return instance->gpio; -} - -UnitempStatus unitemp_singlewire_update(Sensor* sensor) { - SingleWireSensor* instance = sensor->instance; - - //Массив для приёма данных - uint8_t data[5] = {0}; - - /* Запрос */ - //Опускание линии - furi_hal_gpio_write(instance->gpio->pin, false); - //Ожидание более 18 мс - furi_delay_ms(19); - //Выключение прерываний, чтобы ничто не мешало обработке данных - __disable_irq(); - //Подъём линии - furi_hal_gpio_write(instance->gpio->pin, true); - - /* Ответ датчика */ - //Переменная-счётчик - uint16_t timeout = 0; - - //Ожидание подъёма линии - while(!furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - timeout = 0; - - //Ожидание спада линии - while(furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - - //Ожидание подъёма линии - while(!furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - timeout = 0; - - //Ожидание спада линии - while(furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - - /* Чтение данных с датчика*/ - //Приём 5 байт - for(uint8_t a = 0; a < 5; a++) { - for(uint8_t b = 7; b != 255; b--) { - uint16_t hT = 0, lT = 0; - //Пока линия в низком уровне, инкремент переменной lT - while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++; - //Пока линия в высоком уровне, инкремент переменной hT - while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++; - //Если hT больше lT, то пришла единица - if(hT > lT) data[a] |= (1 << b); - } - } - //Включение прерываний - __enable_irq(); - - //Проверка контрольной суммы - if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) { - //Если контрольная сумма не совпала, возврат ошибки - return UT_SENSORSTATUS_BADCRC; - } - - /* Преобразование данных в явный вид */ - //DHT11 и DHT12 - if(sensor->type == &DHT11 || sensor->type == &DHT12_SW) { - sensor->hum = (float)data[0]; - sensor->temp = (float)data[2]; - - //Проверка на отрицательность температуры - if(data[3] != 0) { - //Проверка знака - if(!(data[3] & (1 << 7))) { - //Добавление положительной дробной части - sensor->temp += data[3] * 0.1f; - } else { - //А тут делаем отрицательное значение - data[3] &= ~(1 << 7); - sensor->temp += data[3] * 0.1f; - sensor->temp *= -1; - } - } - } - - //DHT21, DHT22, AM2320 - if(sensor->type == &DHT21 || sensor->type == &DHT22 || sensor->type == &AM2320_SW) { - sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10; - - uint16_t raw = (((uint16_t)data[2] << 8) | data[3]); - //Проверка на отрицательность температуры - if(READ_BIT(raw, 1 << 15)) { - //Проверка на способ кодирования данных - if(READ_BIT(raw, 0x6000)) { - //Не оригинал - sensor->temp = (float)((int16_t)raw) / 10; - } else { - //Оригинальный датчик - CLEAR_BIT(raw, 1 << 15); - sensor->temp = (float)(raw) / -10; - } - } else { - sensor->temp = (float)(raw) / 10; - } - } - //Возврат признака успешного опроса - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/interfaces/SingleWireSensor.h b/applications/external/unitemp/interfaces/SingleWireSensor.h deleted file mode 100644 index c762ff0aa..000000000 --- a/applications/external/unitemp/interfaces/SingleWireSensor.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SINGLE_WIRE -#define UNITEMP_SINGLE_WIRE - -#include "../unitemp.h" -#include "../Sensors.h" - -//Интерфейс Single Wire -typedef struct { - //Порт подключения датчика - const GPIO* gpio; -} SingleWireSensor; - -/* Датчики */ -extern const SensorType DHT11; -extern const SensorType DHT12_SW; -extern const SensorType DHT21; -extern const SensorType DHT22; -extern const SensorType AM2320_SW; - -/** - * @brief Инициализация датчика - * - * @param sensor Указатель на инициализируемый датчик - * @return Истина если всё прошло успешно - */ -bool unitemp_singlewire_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на инициализируемый датчик - * @return Истина если всё прошло успешно - */ -bool unitemp_singlewire_deinit(Sensor* sensor); - -/** - * @brief Получение данных с датчика по однопроводному интерфейсу DHTxx и AM2xxx - * - * @param sensor Указатель на датчик - * @return Статус опроса - */ -UnitempStatus unitemp_singlewire_update(Sensor* sensor); - -/** - * @brief Установить порт датчика - * - * @param sensor Указатель на датчик - * @param gpio Устанавливаемый порт - * @return Истина если всё ок - */ -bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio); - -/** - * @brief Получить порт датчика - * - * @param sensor Указатель на датчик - * @return Указатель на GPIO - */ -const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor); - -/** - * @brief Выделение памяти под датчик на линии One Wire - * - * @param sensor Указатель на датчик - * @param args Указатель на массив с аргументами параметров датчка - */ -bool unitemp_singlewire_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_singlewire_free(Sensor* sensor); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/endianness.h b/applications/external/unitemp/interfaces/endianness.h deleted file mode 100644 index c4a3f4b87..000000000 --- a/applications/external/unitemp/interfaces/endianness.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Avilov Vasily on 10.06.2023. -// - -#ifndef FLIPPERZERO_FIRMWARE_ENDIANNESS_H -#define FLIPPERZERO_FIRMWARE_ENDIANNESS_H - -inline static void store16(uint8_t* b, uint16_t i) { - memcpy(b, &i, 2); -} - -inline static void store32(uint8_t* b, uint32_t i) { - memcpy(b, &i, 4); -} - -inline static uint16_t load16(uint8_t* b) { - uint16_t x; - memcpy(&x, b, 2); - return x; -} - -inline static uint32_t load32(uint8_t* b) { - uint32_t x; - memcpy(&x, b, 4); - return x; -} - -#if BYTE_ORDER == BIG_ENDIAN -#define htobe16(x) (x) -#define htobe32(x) (x) -#define htole16(x) __builtin_bswap16(x) -#define htole32(x) __builtin_bswap32(x) -#define be16toh(x) (x) -#define be32toh(x) (x) -#define le16toh(x) __builtin_bswap16(x) -#define le32toh(x) __builtin_bswap32(x) -#elif BYTE_ORDER == LITTLE_ENDIAN -#define htobe16(x) __builtin_bswap16(x) -#define htobe32(x) __builtin_bswap32(x) -#define htole16(x) (x) -#define htole32(x) (x) -#define be16toh(x) __builtin_bswap16(x) -#define be32toh(x) __builtin_bswap32(x) -#define le16toh(x) (x) -#define le32toh(x) (x) -#else -#error "What kind of system is this?" -#endif - -#define load16_le(b) (le16toh(load16(b))) -#define load32_le(b) (le32toh(load32(b))) -#define store16_le(b, i) (store16(b, htole16(i))) -#define store32_le(b, i) (store32(b, htole32(i))) - -#define load16_be(b) (be16toh(load16(b))) -#define load32_be(b) (be32toh(load32(b))) -#define store16_be(b, i) (store16(b, htobe16(i))) -#define store32_be(b, i) (store32(b, htobe32(i))) - -#endif //FLIPPERZERO_FIRMWARE_ENDIANNESS_H diff --git a/applications/external/unitemp/sensors/AM2320.c b/applications/external/unitemp/sensors/AM2320.c deleted file mode 100644 index 29b255e1d..000000000 --- a/applications/external/unitemp/sensors/AM2320.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "AM2320.h" -#include "../interfaces/I2CSensor.h" - -const SensorType AM2320_I2C = { - .typename = "AM2320_I2C", - .altname = "AM2320 (I2C)", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 2000, - .allocator = unitemp_AM2320_I2C_alloc, - .mem_releaser = unitemp_AM2320_I2C_free, - .initializer = unitemp_AM2320_init, - .deinitializer = unitemp_AM2320_I2C_deinit, - .updater = unitemp_AM2320_I2C_update}; - -static uint16_t AM2320_calc_CRC(uint8_t* ptr, uint8_t len) { - uint16_t crc = 0xFFFF; - uint8_t i; - while(len--) { - crc ^= *ptr++; - for(i = 0; i < 8; i++) { - if(crc & 0x01) { - crc >>= 1; - crc ^= 0xA001; - } else { - crc >>= 1; - } - } - } - return crc; -} - -bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x5C << 1; - i2c_sensor->maxI2CAdr = 0x5C << 1; - return true; -} - -bool unitemp_AM2320_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_AM2320_init(Sensor* sensor) { - //Нечего инициализировать - UNUSED(sensor); - return true; -} - -bool unitemp_AM2320_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[8] = {0x03, 0x00, 0x04}; - - //Wake up - unitemp_i2c_isDeviceReady(i2c_sensor); - furi_delay_ms(1); - - //Запрос - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(2); - //Ответ - if(!unitemp_i2c_readArray(i2c_sensor, 8, data)) return UT_SENSORSTATUS_TIMEOUT; - - if(AM2320_calc_CRC(data, 6) != ((data[7] << 8) | data[6])) { - return UT_SENSORSTATUS_BADCRC; - } - - sensor->hum = (float)(((uint16_t)data[2] << 8) | data[3]) / 10; - //Проверка на отрицательность температуры - if(!(data[4] & (1 << 7))) { - sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / 10; - } else { - data[4] &= ~(1 << 7); - sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / -10; - } - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/AM2320.h b/applications/external/unitemp/sensors/AM2320.h deleted file mode 100644 index fa5f502d4..000000000 --- a/applications/external/unitemp/sensors/AM2320.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_AM2320 -#define UNITEMP_AM2320 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType AM2320_I2C; -/** - * @brief Выделение памяти и установка начальных значений датчика AM2320 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика AM2320 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_AM2320_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_AM2320_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_AM2320_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BME680.c b/applications/external/unitemp/sensors/BME680.c deleted file mode 100644 index 397e702cb..000000000 --- a/applications/external/unitemp/sensors/BME680.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by g0gg0 (https://github.com/g3gg0) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BME680.h" - -const SensorType BME680 = { - .typename = "BME680", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - .pollingInterval = 500, - .allocator = unitemp_BME680_alloc, - .mem_releaser = unitemp_BME680_free, - .initializer = unitemp_BME680_init, - .deinitializer = unitemp_BME680_deinit, - .updater = unitemp_BME680_update}; - -//Интервал обновления калибровочных значений -#define BOSCH_CAL_UPDATE_INTERVAL 60000 - -#define BME680_ID 0x61 - -#define BME680_I2C_ADDR_MIN (0x76 << 1) -#define BME680_I2C_ADDR_MAX (0x77 << 1) - -#define BME680_REG_STATUS 0x1D -#define BME680_REG_CTRL_MEAS 0x74 -#define BME680_REG_CONFIG 0x75 -#define BME680_REG_CTRL_HUM 0x72 -//Преддескретизация температуры -#define BME680_TEMP_OVERSAMPLING_SKIP 0b00000000 -#define BME680_TEMP_OVERSAMPLING_1 0b00100000 -#define BME680_TEMP_OVERSAMPLING_2 0b01000000 -#define BME680_TEMP_OVERSAMPLING_4 0b01100000 -#define BME680_TEMP_OVERSAMPLING_8 0b10000000 -#define BME680_TEMP_OVERSAMPLING_16 0b10100000 -//Преддескретизация давления -#define BME680_PRESS_OVERSAMPLING_SKIP 0b00000000 -#define BME680_PRESS_OVERSAMPLING_1 0b00000100 -#define BME680_PRESS_OVERSAMPLING_2 0b00001000 -#define BME680_PRESS_OVERSAMPLING_4 0b00001100 -#define BME680_PRESS_OVERSAMPLING_8 0b00010000 -#define BME680_PRESS_OVERSAMPLING_16 0b00010100 -//Преддескретизация влажности -#define BME680_HUM_OVERSAMPLING_SKIP 0b00000000 -#define BME680_HUM_OVERSAMPLING_1 0b00000001 -#define BME680_HUM_OVERSAMPLING_2 0b00000010 -#define BME680_HUM_OVERSAMPLING_4 0b00000011 -#define BME680_HUM_OVERSAMPLING_8 0b00000100 -#define BME680_HUM_OVERSAMPLING_16 0b00000101 -//Режимы работы датчика -#define BME680_MODE_SLEEP 0b00000000 //Наелся и спит -#define BME680_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон -//Коэффициент фильтрации значений -#define BME680_FILTER_COEFF_1 0b00000000 -#define BME680_FILTER_COEFF_2 0b00000100 -#define BME680_FILTER_COEFF_4 0b00001000 -#define BME680_FILTER_COEFF_8 0b00001100 -#define BME680_FILTER_COEFF_16 0b00010000 -//Разрешить работу по SPI -#define BME680_SPI_3W_ENABLE 0b00000001 -#define BME680_SPI_3W_DISABLE 0b00000000 - -/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680.c or - https://github.com/boschsensortec/BME68x-Sensor-API */ -static float BME680_compensate_temperature(I2CSensor* i2c_sensor, int32_t temp_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - float var1 = 0; - float var2 = 0; - float calc_temp = 0; - - /* calculate var1 data */ - var1 = - ((((float)temp_adc / 16384.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 1024.0f)) * - ((float)bme680_instance->temp_cal.dig_T2)); - - /* calculate var2 data */ - var2 = - (((((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f)) * - (((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f))) * - ((float)bme680_instance->temp_cal.dig_T3 * 16.0f)); - - /* t_fine value*/ - bme680_instance->t_fine = (var1 + var2); - - /* compensated temperature data*/ - calc_temp = ((bme680_instance->t_fine) / 5120.0f); - - return calc_temp; -} - -static float BME680_compensate_pressure(I2CSensor* i2c_sensor, int32_t pres_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - - float var1; - float var2; - float var3; - float calc_pres; - - var1 = (((float)bme680_instance->t_fine / 2.0f) - 64000.0f); - var2 = var1 * var1 * (((float)bme680_instance->press_cal.dig_P6) / (131072.0f)); - var2 = var2 + (var1 * ((float)bme680_instance->press_cal.dig_P5) * 2.0f); - var2 = (var2 / 4.0f) + (((float)bme680_instance->press_cal.dig_P4) * 65536.0f); - var1 = - (((((float)bme680_instance->press_cal.dig_P3 * var1 * var1) / 16384.0f) + - ((float)bme680_instance->press_cal.dig_P2 * var1)) / - 524288.0f); - var1 = ((1.0f + (var1 / 32768.0f)) * ((float)bme680_instance->press_cal.dig_P1)); - calc_pres = (1048576.0f - ((float)pres_adc)); - - /* Avoid exception caused by division by zero */ - if((int)var1 != 0) { - calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); - var1 = - (((float)bme680_instance->press_cal.dig_P9) * calc_pres * calc_pres) / 2147483648.0f; - var2 = calc_pres * (((float)bme680_instance->press_cal.dig_P8) / 32768.0f); - var3 = - ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) * - (bme680_instance->press_cal.dig_P10 / 131072.0f)); - calc_pres = - (calc_pres + - (var1 + var2 + var3 + ((float)bme680_instance->press_cal.dig_P7 * 128.0f)) / 16.0f); - } else { - calc_pres = 0; - } - - return calc_pres; -} - -static float BME680_compensate_humidity(I2CSensor* i2c_sensor, int32_t hum_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - float calc_hum; - float var1; - float var2; - float var3; - float var4; - float temp_comp; - - /* compensated temperature data*/ - temp_comp = ((bme680_instance->t_fine) / 5120.0f); - var1 = - (float)((float)hum_adc) - (((float)bme680_instance->hum_cal.dig_H1 * 16.0f) + - (((float)bme680_instance->hum_cal.dig_H3 / 2.0f) * temp_comp)); - var2 = var1 * - ((float)(((float)bme680_instance->hum_cal.dig_H2 / 262144.0f) * - (1.0f + (((float)bme680_instance->hum_cal.dig_H4 / 16384.0f) * temp_comp) + - (((float)bme680_instance->hum_cal.dig_H5 / 1048576.0f) * temp_comp * temp_comp)))); - var3 = (float)bme680_instance->hum_cal.dig_H6 / 16384.0f; - var4 = (float)bme680_instance->hum_cal.dig_H7 / 2097152.0f; - calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); - if(calc_hum > 100.0f) { - calc_hum = 100.0f; - } else if(calc_hum < 0.0f) { - calc_hum = 0.0f; - } - - return calc_hum; -} - -/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680_defs.h */ -#define BME680_COEFF_SIZE UINT8_C(41) -#define BME680_COEFF_ADDR1_LEN UINT8_C(25) -#define BME680_COEFF_ADDR2_LEN UINT8_C(16) -#define BME680_COEFF_ADDR1 UINT8_C(0x89) -#define BME680_COEFF_ADDR2 UINT8_C(0xe1) -#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) -#define BME680_T2_LSB_REG (1) -#define BME680_T2_MSB_REG (2) -#define BME680_T3_REG (3) -#define BME680_P1_LSB_REG (5) -#define BME680_P1_MSB_REG (6) -#define BME680_P2_LSB_REG (7) -#define BME680_P2_MSB_REG (8) -#define BME680_P3_REG (9) -#define BME680_P4_LSB_REG (11) -#define BME680_P4_MSB_REG (12) -#define BME680_P5_LSB_REG (13) -#define BME680_P5_MSB_REG (14) -#define BME680_P7_REG (15) -#define BME680_P6_REG (16) -#define BME680_P8_LSB_REG (19) -#define BME680_P8_MSB_REG (20) -#define BME680_P9_LSB_REG (21) -#define BME680_P9_MSB_REG (22) -#define BME680_P10_REG (23) -#define BME680_H2_MSB_REG (25) -#define BME680_H2_LSB_REG (26) -#define BME680_H1_LSB_REG (26) -#define BME680_H1_MSB_REG (27) -#define BME680_H3_REG (28) -#define BME680_H4_REG (29) -#define BME680_H5_REG (30) -#define BME680_H6_REG (31) -#define BME680_H7_REG (32) -#define BME680_T1_LSB_REG (33) -#define BME680_T1_MSB_REG (34) -#define BME680_GH2_LSB_REG (35) -#define BME680_GH2_MSB_REG (36) -#define BME680_GH1_REG (37) -#define BME680_GH3_REG (38) -#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) -#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) - -static bool BME680_readCalValues(I2CSensor* i2c_sensor) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - uint8_t coeff_array[BME680_COEFF_SIZE] = {0}; - - if(!unitemp_i2c_readRegArray( - i2c_sensor, BME680_COEFF_ADDR1, BME680_COEFF_ADDR1_LEN, &coeff_array[0])) - return false; - if(!unitemp_i2c_readRegArray( - i2c_sensor, - BME680_COEFF_ADDR2, - BME680_COEFF_ADDR2_LEN, - &coeff_array[BME680_COEFF_ADDR1_LEN])) - return false; - - /* Temperature related coefficients */ - bme680_instance->temp_cal.dig_T1 = (uint16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_T1_MSB_REG], coeff_array[BME680_T1_LSB_REG])); - bme680_instance->temp_cal.dig_T2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_T2_MSB_REG], coeff_array[BME680_T2_LSB_REG])); - bme680_instance->temp_cal.dig_T3 = (int8_t)(coeff_array[BME680_T3_REG]); - - /* Pressure related coefficients */ - bme680_instance->press_cal.dig_P1 = (uint16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P1_MSB_REG], coeff_array[BME680_P1_LSB_REG])); - bme680_instance->press_cal.dig_P2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P2_MSB_REG], coeff_array[BME680_P2_LSB_REG])); - bme680_instance->press_cal.dig_P3 = (int8_t)coeff_array[BME680_P3_REG]; - bme680_instance->press_cal.dig_P4 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P4_MSB_REG], coeff_array[BME680_P4_LSB_REG])); - bme680_instance->press_cal.dig_P5 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P5_MSB_REG], coeff_array[BME680_P5_LSB_REG])); - bme680_instance->press_cal.dig_P6 = (int8_t)(coeff_array[BME680_P6_REG]); - bme680_instance->press_cal.dig_P7 = (int8_t)(coeff_array[BME680_P7_REG]); - bme680_instance->press_cal.dig_P8 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P8_MSB_REG], coeff_array[BME680_P8_LSB_REG])); - bme680_instance->press_cal.dig_P9 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P9_MSB_REG], coeff_array[BME680_P9_LSB_REG])); - bme680_instance->press_cal.dig_P10 = (uint8_t)(coeff_array[BME680_P10_REG]); - - /* Humidity related coefficients */ - bme680_instance->hum_cal.dig_H1 = - (uint16_t)(((uint16_t)coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); - bme680_instance->hum_cal.dig_H2 = - (uint16_t)(((uint16_t)coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); - bme680_instance->hum_cal.dig_H3 = (int8_t)coeff_array[BME680_H3_REG]; - bme680_instance->hum_cal.dig_H4 = (int8_t)coeff_array[BME680_H4_REG]; - bme680_instance->hum_cal.dig_H5 = (int8_t)coeff_array[BME680_H5_REG]; - bme680_instance->hum_cal.dig_H6 = (uint8_t)coeff_array[BME680_H6_REG]; - bme680_instance->hum_cal.dig_H7 = (int8_t)coeff_array[BME680_H7_REG]; - - /* Gas heater related coefficients */ - bme680_instance->gas_cal.dig_GH1 = (int8_t)coeff_array[BME680_GH1_REG]; - bme680_instance->gas_cal.dig_GH2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG])); - bme680_instance->gas_cal.dig_GH3 = (int8_t)coeff_array[BME680_GH3_REG]; - -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, - "Sensor BME680 T1-T3: %d, %d, %d", - bme680_instance->temp_cal.dig_T1, - bme680_instance->temp_cal.dig_T2, - bme680_instance->temp_cal.dig_T3); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680: P1-P10: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", - bme680_instance->press_cal.dig_P1, - bme680_instance->press_cal.dig_P2, - bme680_instance->press_cal.dig_P3, - bme680_instance->press_cal.dig_P4, - bme680_instance->press_cal.dig_P5, - bme680_instance->press_cal.dig_P6, - bme680_instance->press_cal.dig_P7, - bme680_instance->press_cal.dig_P8, - bme680_instance->press_cal.dig_P9, - bme680_instance->press_cal.dig_P10); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680: H1-H7: %d, %d, %d, %d, %d, %d, %d", - bme680_instance->hum_cal.dig_H1, - bme680_instance->hum_cal.dig_H2, - bme680_instance->hum_cal.dig_H3, - bme680_instance->hum_cal.dig_H4, - bme680_instance->hum_cal.dig_H5, - bme680_instance->hum_cal.dig_H6, - bme680_instance->hum_cal.dig_H7); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680 GH1-GH3: %d, %d, %d", - bme680_instance->gas_cal.dig_GH1, - bme680_instance->gas_cal.dig_GH2, - bme680_instance->gas_cal.dig_GH3); - -#endif - - bme680_instance->last_cal_update_time = furi_get_tick(); - return true; -} -static bool BME680_isMeasuring(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return (bool)(unitemp_i2c_readReg(i2c_sensor, BME680_REG_STATUS) & 0x20); -} - -bool unitemp_BME680_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BME680_instance* bme680_instance = malloc(sizeof(BME680_instance)); - if(bme680_instance == NULL) { - FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); - return false; - } - - if(sensor->type == &BME680) bme680_instance->chip_id = BME680_ID; - - i2c_sensor->sensorInstance = bme680_instance; - - i2c_sensor->minI2CAdr = BME680_I2C_ADDR_MIN; - i2c_sensor->maxI2CAdr = BME680_I2C_ADDR_MAX; - return true; -} - -bool unitemp_BME680_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перезагрузка - unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); - //Чтение ID датчика - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != BME680_ID) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x%02X", - sensor->name, - id, - BME680_ID); - return false; - } - - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_HUM, - (unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_HUM) & ~7) | BME680_HUM_OVERSAMPLING_1); - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_MEAS, - BME680_TEMP_OVERSAMPLING_2 | BME680_PRESS_OVERSAMPLING_4 | BME680_MODE_FORCED); - //Настройка периода опроса и фильтрации значений - unitemp_i2c_writeReg( - i2c_sensor, BME680_REG_CONFIG, BME680_FILTER_COEFF_16 | BME680_SPI_3W_DISABLE); - //Чтение калибровочных значений - if(!BME680_readCalValues(i2c_sensor)) { - FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); - return false; - } - return true; -} - -bool unitemp_BME680_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перевод в сон - unitemp_i2c_writeReg(i2c_sensor, BME680_REG_CTRL_MEAS, BME680_MODE_SLEEP); - return true; -} - -UnitempStatus unitemp_BME680_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BME680_instance* instance = i2c_sensor->sensorInstance; - - uint32_t t = furi_get_tick(); - - uint8_t buff[3]; - //Проверка инициализированности датчика - unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); - if(buff[0] == 0) { - FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_MEAS, - unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_MEAS) | 1); - - while(BME680_isMeasuring(sensor)) { - if(furi_get_tick() - t > 100) { - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { - BME680_readCalValues(i2c_sensor); - } - - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x1F, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x22, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x25, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; - - sensor->temp = BME680_compensate_temperature(i2c_sensor, adc_T); - sensor->pressure = BME680_compensate_pressure(i2c_sensor, adc_P); - sensor->hum = BME680_compensate_humidity(i2c_sensor, adc_H); - - return UT_SENSORSTATUS_OK; -} - -bool unitemp_BME680_free(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BME680.h b/applications/external/unitemp/sensors/BME680.h deleted file mode 100644 index dabdaca8e..000000000 --- a/applications/external/unitemp/sensors/BME680.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by g0gg0 (https://github.com/g3gg0) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BME680 -#define UNITEMP_BME680 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; -} BME680_temp_cal; - -typedef struct { - uint16_t dig_GH1; - int16_t dig_GH2; - int16_t dig_GH3; -} BME680_gas_cal; - -typedef struct { - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; - int16_t dig_P10; -} BME680_press_cal; - -typedef struct { - uint16_t dig_H1; - uint16_t dig_H2; - int8_t dig_H3; - int8_t dig_H4; - int8_t dig_H5; - uint8_t dig_H6; - int8_t dig_H7; -} BME680_hum_cal; - -typedef struct { - //Калибровочные значения температуры - BME680_temp_cal temp_cal; - //Калибровочные значения давления - BME680_press_cal press_cal; - //Калибровочные значения влажности воздуха - BME680_hum_cal hum_cal; - BME680_gas_cal gas_cal; - //Время последнего обновления калибровочных значений - uint32_t last_cal_update_time; - //Индификатор датчика - uint8_t chip_id; - //Корректировочное значение температуры - int32_t t_fine; -} BME680_instance; - -extern const SensorType BME680; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP680 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BME680_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP680 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BME680_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BME680_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_BME680_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BME680_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMP180.c b/applications/external/unitemp/sensors/BMP180.c deleted file mode 100644 index 72cff069e..000000000 --- a/applications/external/unitemp/sensors/BMP180.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BMP180.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - int16_t AC1; - int16_t AC2; - int16_t AC3; - uint16_t AC4; - uint16_t AC5; - uint16_t AC6; - int16_t B1; - int16_t B2; - int16_t MB; - int16_t MC; - int16_t MD; -} BMP180_cal; - -typedef struct { - //Калибровочные значения - BMP180_cal bmp180_cal; -} BMP180_instance; - -const SensorType BMP180 = { - .typename = "BMP180", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_PRESSURE, - .pollingInterval = 1000, - .allocator = unitemp_BMP180_I2C_alloc, - .mem_releaser = unitemp_BMP180_I2C_free, - .initializer = unitemp_BMP180_init, - .deinitializer = unitemp_BMP180_I2C_deinit, - .updater = unitemp_BMP180_I2C_update}; - -bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x77 << 1; - i2c_sensor->maxI2CAdr = 0x77 << 1; - - BMP180_instance* bmx180_instance = malloc(sizeof(BMP180_instance)); - i2c_sensor->sensorInstance = bmx180_instance; - return true; -} - -bool unitemp_BMP180_I2C_free(Sensor* sensor) { - UNUSED(sensor); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} - -bool unitemp_BMP180_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Перезагрузка - if(!unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6)) return false; - furi_delay_ms(100); - - //Проверка ID - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != 0x55) { - FURI_LOG_E( - APP_NAME, "Sensor %s returned wrong ID 0x%02X, expected 0x55", sensor->name, id); - return false; - } - - BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; - - uint8_t buff[22] = {0}; - - //Чтение калибровочных значений - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xAA, 22, buff)) return false; - bmp180_instance->bmp180_cal.AC1 = (buff[0] << 8) | buff[1]; - bmp180_instance->bmp180_cal.AC2 = (buff[2] << 8) | buff[3]; - bmp180_instance->bmp180_cal.AC3 = (buff[4] << 8) | buff[5]; - bmp180_instance->bmp180_cal.AC4 = (buff[6] << 8) | buff[7]; - bmp180_instance->bmp180_cal.AC5 = (buff[8] << 8) | buff[9]; - bmp180_instance->bmp180_cal.AC6 = (buff[10] << 8) | buff[11]; - bmp180_instance->bmp180_cal.B1 = (buff[12] << 8) | buff[13]; - bmp180_instance->bmp180_cal.B2 = (buff[14] << 8) | buff[15]; - bmp180_instance->bmp180_cal.MB = (buff[16] << 8) | buff[17]; - bmp180_instance->bmp180_cal.MC = (buff[18] << 8) | buff[19]; - bmp180_instance->bmp180_cal.MD = (buff[20] << 8) | buff[21]; - - UNITEMP_DEBUG( - "Sensor BMP180 (0x%02X) calibration values: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmp180_instance->bmp180_cal.AC1, - bmp180_instance->bmp180_cal.AC2, - bmp180_instance->bmp180_cal.AC3, - bmp180_instance->bmp180_cal.AC4, - bmp180_instance->bmp180_cal.AC5, - bmp180_instance->bmp180_cal.AC6, - bmp180_instance->bmp180_cal.B1, - bmp180_instance->bmp180_cal.B2, - bmp180_instance->bmp180_cal.MB, - bmp180_instance->bmp180_cal.MC, - bmp180_instance->bmp180_cal.MD); - return true; -} - -bool unitemp_BMP180_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; - - //Чтение температуры - if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x2E)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(5); - uint8_t buff[3] = {0}; - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t UT = ((uint16_t)buff[0] << 8) + buff[1]; - int32_t X1 = (UT - bmp180_instance->bmp180_cal.AC6) * bmp180_instance->bmp180_cal.AC5 >> 15; - int32_t X2 = (bmp180_instance->bmp180_cal.MC << 11) / (X1 + bmp180_instance->bmp180_cal.MD); - int32_t B5 = X1 + X2; - sensor->temp = ((B5 + 8) / 16) * 0.1f; - - //Чтение давления - if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x34 + (0b11 << 6))) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(26); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - uint32_t UP = ((buff[0] << 16) + (buff[1] << 8) + buff[2]) >> (8 - 0b11); - - int32_t B6, X3, B3, P; - uint32_t B4, B7; - B6 = B5 - 4000; - X1 = (bmp180_instance->bmp180_cal.B2 * ((B6 * B6) >> 12)) >> 11; - X2 = (bmp180_instance->bmp180_cal.AC2 * B6) >> 11; - X3 = X1 + X2; - B3 = (((bmp180_instance->bmp180_cal.AC1 * 4 + X3) << 0b11) + 2) >> 2; - X1 = (bmp180_instance->bmp180_cal.AC3 * B6) >> 13; - X2 = (bmp180_instance->bmp180_cal.B1 * ((B6 * B6) >> 12)) >> 16; - X3 = ((X1 + X2) + 2) >> 2; - B4 = (bmp180_instance->bmp180_cal.AC4 * (unsigned long)(X3 + 32768)) >> 15; - B7 = ((unsigned long)UP - B3) * (50000 >> 0b11); - if(B7 < 0x80000000) - P = (B7 * 2) / B4; - else - P = (B7 / B4) * 2; - X1 = (P >> 8) * (P >> 8); - X1 = (X1 * 3038) >> 16; - X2 = (-7357 * (P)) >> 16; - P = P + ((X1 + X2 + 3791) >> 4); - sensor->pressure = P; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/BMP180.h b/applications/external/unitemp/sensors/BMP180.h deleted file mode 100644 index ce2569092..000000000 --- a/applications/external/unitemp/sensors/BMP180.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BMP180 -#define UNITEMP_BMP180 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType BMP180; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP180 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP180 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BMP180_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_BMP180_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_BMP180_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMx280.c b/applications/external/unitemp/sensors/BMx280.c deleted file mode 100644 index db445d330..000000000 --- a/applications/external/unitemp/sensors/BMx280.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BMx280.h" - -const SensorType BMP280 = { - .typename = "BMP280", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_PRESSURE, - .pollingInterval = 500, - .allocator = unitemp_BMx280_alloc, - .mem_releaser = unitemp_BMx280_free, - .initializer = unitemp_BMx280_init, - .deinitializer = unitemp_BMx280_deinit, - .updater = unitemp_BMx280_update}; -const SensorType BME280 = { - .typename = "BME280", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - - .pollingInterval = 500, - .allocator = unitemp_BMx280_alloc, - .mem_releaser = unitemp_BMx280_free, - .initializer = unitemp_BMx280_init, - .deinitializer = unitemp_BMx280_deinit, - .updater = unitemp_BMx280_update}; - -//Интервал обновления калибровочных значений -#define BOSCH_CAL_UPDATE_INTERVAL 60000 - -#define TEMP_CAL_START_ADDR 0x88 -#define PRESS_CAL_START_ADDR 0x8E -#define HUM_CAL_H1_ADDR 0xA1 -#define HUM_CAL_H2_ADDR 0xE1 - -#define BMP280_ID 0x58 -#define BME280_ID 0x60 - -#define BMx280_I2C_ADDR_MIN (0x76 << 1) -#define BMx280_I2C_ADDR_MAX (0x77 << 1) - -#define BMx280_REG_STATUS 0xF3 -#define BMx280_REG_CTRL_MEAS 0xF4 -#define BMx280_REG_CONFIG 0xF5 -#define BME280_REG_CTRL_HUM 0xF2 -//Преддескретизация температуры -#define BMx280_TEMP_OVERSAMPLING_SKIP 0b00000000 -#define BMx280_TEMP_OVERSAMPLING_1 0b00100000 -#define BMx280_TEMP_OVERSAMPLING_2 0b01000000 -#define BMx280_TEMP_OVERSAMPLING_4 0b01100000 -#define BMx280_TEMP_OVERSAMPLING_8 0b10000000 -#define BMx280_TEMP_OVERSAMPLING_16 0b10100000 -//Преддескретизация давления -#define BMx280_PRESS_OVERSAMPLING_SKIP 0b00000000 -#define BMx280_PRESS_OVERSAMPLING_1 0b00000100 -#define BMx280_PRESS_OVERSAMPLING_2 0b00001000 -#define BMx280_PRESS_OVERSAMPLING_4 0b00001100 -#define BMx280_PRESS_OVERSAMPLING_8 0b00010000 -#define BMx280_PRESS_OVERSAMPLING_16 0b00010100 -//Преддескретизация влажности -#define BME280_HUM_OVERSAMPLING_SKIP 0b00000000 -#define BME280_HUM_OVERSAMPLING_1 0b00000001 -#define BME280_HUM_OVERSAMPLING_2 0b00000010 -#define BME280_HUM_OVERSAMPLING_4 0b00000011 -#define BME280_HUM_OVERSAMPLING_8 0b00000100 -#define BME280_HUM_OVERSAMPLING_16 0b00000101u -//Режимы работы датчика -#define BMx280_MODE_SLEEP 0b00000000 //Наелся и спит -#define BMx280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон -#define BMx280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения -//Период обновления в нормальном режиме -#define BMx280_STANDBY_TIME_0_5 0b00000000 -#define BMx280_STANDBY_TIME_62_5 0b00100000 -#define BMx280_STANDBY_TIME_125 0b01000000 -#define BMx280_STANDBY_TIME_250 0b01100000 -#define BMx280_STANDBY_TIME_500 0b10000000 -#define BMx280_STANDBY_TIME_1000 0b10100000 -#define BMx280_STANDBY_TIME_2000 0b11000000 -#define BMx280_STANDBY_TIME_4000 0b11100000 -//Коэффициент фильтрации значений -#define BMx280_FILTER_COEFF_1 0b00000000 -#define BMx280_FILTER_COEFF_2 0b00000100 -#define BMx280_FILTER_COEFF_4 0b00001000 -#define BMx280_FILTER_COEFF_8 0b00001100 -#define BMx280_FILTER_COEFF_16 0b00010000 -//Разрешить работу по SPI -#define BMx280_SPI_3W_ENABLE 0b00000001 -#define BMx280_SPI_3W_DISABLE 0b00000000 - -static float BMx280_compensate_temperature(I2CSensor* i2c_sensor, int32_t adc_T) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - int32_t var1, var2; - var1 = ((((adc_T >> 3) - ((int32_t)bmx280_instance->temp_cal.dig_T1 << 1))) * - ((int32_t)bmx280_instance->temp_cal.dig_T2)) >> - 11; - var2 = (((((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1)) * - ((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1))) >> - 12) * - ((int32_t)bmx280_instance->temp_cal.dig_T3)) >> - 14; - bmx280_instance->t_fine = var1 + var2; - return ((bmx280_instance->t_fine * 5 + 128) >> 8) / 100.0f; -} - -static float BMx280_compensate_pressure(I2CSensor* i2c_sensor, int32_t adc_P) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - - int32_t var1, var2; - uint32_t p; - var1 = (((int32_t)bmx280_instance->t_fine) >> 1) - (int32_t)64000; - var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmx280_instance->press_cal.dig_P6); - var2 = var2 + ((var1 * ((int32_t)bmx280_instance->press_cal.dig_P5)) << 1); - var2 = (var2 >> 2) + (((int32_t)bmx280_instance->press_cal.dig_P4) << 16); - var1 = (((bmx280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + - ((((int32_t)bmx280_instance->press_cal.dig_P2) * var1) >> 1)) >> - 18; - var1 = ((((32768 + var1)) * ((int32_t)bmx280_instance->press_cal.dig_P1)) >> 15); - if(var1 == 0) { - return 0; // avoid exception caused by division by zero - } - p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125; - if(p < 0x80000000) { - p = (p << 1) / ((uint32_t)var1); - } else { - p = (p / (uint32_t)var1) * 2; - } - var1 = (((int32_t)bmx280_instance->press_cal.dig_P9) * - ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> - 12; - var2 = (((int32_t)(p >> 2)) * ((int32_t)bmx280_instance->press_cal.dig_P8)) >> 13; - p = (uint32_t)((int32_t)p + ((var1 + var2 + bmx280_instance->press_cal.dig_P7) >> 4)); - return p; -} - -static float BMx280_compensate_humidity(I2CSensor* i2c_sensor, int32_t adc_H) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - int32_t v_x1_u32r; - v_x1_u32r = (bmx280_instance->t_fine - ((int32_t)76800)); - - v_x1_u32r = - (((((adc_H << 14) - (((int32_t)bmx280_instance->hum_cal.dig_H4) << 20) - - (((int32_t)bmx280_instance->hum_cal.dig_H5) * v_x1_u32r)) + - ((int32_t)16384)) >> - 15) * - (((((((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H6)) >> 10) * - (((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H3)) >> 11) + - ((int32_t)32768))) >> - 10) + - ((int32_t)2097152)) * - ((int32_t)bmx280_instance->hum_cal.dig_H2) + - 8192) >> - 14)); - - v_x1_u32r = - (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((int32_t)bmx280_instance->hum_cal.dig_H1)) >> - 4)); - - v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); - v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); - return ((uint32_t)(v_x1_u32r >> 12)) / 1024.0f; -} - -static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - if(!unitemp_i2c_readRegArray( - i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmx280_instance->temp_cal)) - return false; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X) T1-T3: %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->temp_cal.dig_T1, - bmx280_instance->temp_cal.dig_T2, - bmx280_instance->temp_cal.dig_T3); - - if(!unitemp_i2c_readRegArray( - i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmx280_instance->press_cal)) - return false; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X): P1-P9: %d, %d, %d, %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->press_cal.dig_P1, - bmx280_instance->press_cal.dig_P2, - bmx280_instance->press_cal.dig_P3, - bmx280_instance->press_cal.dig_P4, - bmx280_instance->press_cal.dig_P5, - bmx280_instance->press_cal.dig_P6, - bmx280_instance->press_cal.dig_P7, - bmx280_instance->press_cal.dig_P8, - bmx280_instance->press_cal.dig_P9); - - if(bmx280_instance->chip_id == BME280_ID) { - uint8_t buff[7] = {0}; - if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H1_ADDR, 1, buff)) return false; - bmx280_instance->hum_cal.dig_H1 = buff[0]; - - if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H2_ADDR, 7, buff)) return false; - bmx280_instance->hum_cal.dig_H2 = (uint16_t)(buff[0] | ((uint16_t)buff[1] << 8)); - bmx280_instance->hum_cal.dig_H3 = buff[2]; - bmx280_instance->hum_cal.dig_H4 = ((int16_t)buff[3] << 4) | (buff[4] & 0x0F); - bmx280_instance->hum_cal.dig_H5 = (buff[4] & 0x0F) | ((int16_t)buff[5] << 4); - bmx280_instance->hum_cal.dig_H6 = buff[6]; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X): H1-H6: %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->hum_cal.dig_H1, - bmx280_instance->hum_cal.dig_H2, - bmx280_instance->hum_cal.dig_H3, - bmx280_instance->hum_cal.dig_H4, - bmx280_instance->hum_cal.dig_H5, - bmx280_instance->hum_cal.dig_H6); - } - - bmx280_instance->last_cal_update_time = furi_get_tick(); - return true; -} -static bool bmp280_isMeasuring(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return (bool)((unitemp_i2c_readReg(i2c_sensor, BMx280_REG_STATUS) & 0x08) >> 3); -} - -bool unitemp_BMx280_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMx280_instance* bmx280_instance = malloc(sizeof(BMx280_instance)); - if(bmx280_instance == NULL) { - FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); - return false; - } - - if(sensor->type == &BMP280) bmx280_instance->chip_id = BMP280_ID; - if(sensor->type == &BME280) bmx280_instance->chip_id = BME280_ID; - - i2c_sensor->sensorInstance = bmx280_instance; - - i2c_sensor->minI2CAdr = BMx280_I2C_ADDR_MIN; - i2c_sensor->maxI2CAdr = BMx280_I2C_ADDR_MAX; - return true; -} - -bool unitemp_BMx280_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перезагрузка - unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); - //Чтение ID датчика - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != BMP280_ID && id != BME280_ID) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x%02X or 0x%02X", - sensor->name, - id, - BMP280_ID, - BME280_ID); - return false; - } - - //Настройка режимов работы - if(id == BME280_ID) { - unitemp_i2c_writeReg(i2c_sensor, BME280_REG_CTRL_HUM, BME280_HUM_OVERSAMPLING_1); - unitemp_i2c_writeReg( - i2c_sensor, BME280_REG_CTRL_HUM, unitemp_i2c_readReg(i2c_sensor, BME280_REG_CTRL_HUM)); - } - unitemp_i2c_writeReg( - i2c_sensor, - BMx280_REG_CTRL_MEAS, - BMx280_TEMP_OVERSAMPLING_2 | BMx280_PRESS_OVERSAMPLING_4 | BMx280_MODE_NORMAL); - //Настройка периода опроса и фильтрации значений - unitemp_i2c_writeReg( - i2c_sensor, - BMx280_REG_CONFIG, - BMx280_STANDBY_TIME_500 | BMx280_FILTER_COEFF_16 | BMx280_SPI_3W_DISABLE); - //Чтение калибровочных значений - if(!bmx280_readCalValues(i2c_sensor)) { - FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); - return false; - } - return true; -} - -bool unitemp_BMx280_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перевод в сон - unitemp_i2c_writeReg(i2c_sensor, BMx280_REG_CTRL_MEAS, BMx280_MODE_SLEEP); - return true; -} - -UnitempStatus unitemp_BMx280_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMx280_instance* instance = i2c_sensor->sensorInstance; - - uint32_t t = furi_get_tick(); - - uint8_t buff[3]; - //Проверка инициализированности датчика - unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); - if(buff[0] == 0) { - FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - while(bmp280_isMeasuring(sensor)) { - if(furi_get_tick() - t > 100) { - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { - bmx280_readCalValues(i2c_sensor); - } - - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFD, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; - sensor->temp = BMx280_compensate_temperature(i2c_sensor, adc_T); - sensor->pressure = BMx280_compensate_pressure(i2c_sensor, adc_P); - sensor->hum = BMx280_compensate_humidity(i2c_sensor, adc_H); - return UT_SENSORSTATUS_OK; -} - -bool unitemp_BMx280_free(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMx280.h b/applications/external/unitemp/sensors/BMx280.h deleted file mode 100644 index 32027f285..000000000 --- a/applications/external/unitemp/sensors/BMx280.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BMx280 -#define UNITEMP_BMx280 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; -} BMx280_temp_cal; - -typedef struct { - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; -} BMx280_press_cal; - -typedef struct { - uint8_t dig_H1; - int16_t dig_H2; - uint8_t dig_H3; - int16_t dig_H4; - int16_t dig_H5; - int8_t dig_H6; -} BMx280_hum_cal; - -typedef struct { - //Калибровочные значения температуры - BMx280_temp_cal temp_cal; - //Калибровочные значения давления - BMx280_press_cal press_cal; - //Калибровочные значения влажности воздуха - BMx280_hum_cal hum_cal; - //Время последнего обновления калибровочных значений - uint32_t last_cal_update_time; - //Индификатор датчика - uint8_t chip_id; - //Корректировочное значение температуры - int32_t t_fine; -} BMx280_instance; - -extern const SensorType BMP280; -extern const SensorType BME280; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP280 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BMx280_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP280 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BMx280_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BMx280_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_BMx280_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BMx280_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/DHT20.c b/applications/external/unitemp/sensors/DHT20.c deleted file mode 100644 index ce11fe3d6..000000000 --- a/applications/external/unitemp/sensors/DHT20.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "DHT20.h" -#include "../interfaces/I2CSensor.h" - -const SensorType DHT20 = { - .typename = "DHT20", - .altname = "DHT20/AM2108/AHT20", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_DHT20_I2C_alloc, - .mem_releaser = unitemp_DHT20_I2C_free, - .initializer = unitemp_DHT20_init, - .deinitializer = unitemp_DHT20_I2C_deinit, - .updater = unitemp_DHT20_I2C_update}; -const SensorType AHT10 = { - .typename = "AHT10", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_DHT20_I2C_alloc, - .mem_releaser = unitemp_DHT20_I2C_free, - .initializer = unitemp_DHT20_init, - .deinitializer = unitemp_DHT20_I2C_deinit, - .updater = unitemp_DHT20_I2C_update}; - -static uint8_t DHT20_get_status(I2CSensor* i2c_sensor) { - uint8_t status[1] = {0}; - unitemp_i2c_readArray(i2c_sensor, 1, status); - return status[0]; -} - -static uint8_t DHT20_calc_CRC8(uint8_t* message, uint8_t Num) { - uint8_t i; - uint8_t byte; - uint8_t crc = 0xFF; - for(byte = 0; byte < Num; byte++) { - crc ^= (message[byte]); - for(i = 8; i > 0; --i) { - if(crc & 0x80) - crc = (crc << 1) ^ 0x31; - else - crc = (crc << 1); - } - } - return crc; -} - -static void DHT20_reset_reg(I2CSensor* i2c_sensor, uint8_t addr) { - uint8_t data[3] = {addr, 0x00, 0x00}; - - unitemp_i2c_writeArray(i2c_sensor, 3, data); - - furi_delay_ms(5); - - unitemp_i2c_readArray(i2c_sensor, 3, data); - - furi_delay_ms(10); - - data[0] = 0xB0 | addr; - unitemp_i2c_writeArray(i2c_sensor, 3, data); -} - -bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x38 << 1; - i2c_sensor->maxI2CAdr = (sensor->type == &DHT20) ? (0x38 << 1) : (0x39 << 1); - return true; -} - -bool unitemp_DHT20_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_DHT20_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[3] = {0xA8, 0x00, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; - furi_delay_ms(10); - data[0] = (sensor->type == &DHT20) ? 0xBE : 0xE1; - data[1] = 0x08; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; - furi_delay_ms(10); - - return true; -} - -bool unitemp_DHT20_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - if(DHT20_get_status(i2c_sensor) != 0x18) { - DHT20_reset_reg(i2c_sensor, 0x1B); - DHT20_reset_reg(i2c_sensor, 0x1C); - DHT20_reset_reg(i2c_sensor, 0x1E); - } - furi_delay_ms(10); - - uint8_t data[7] = {0xAC, 0x33, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(80); - uint32_t t = furi_get_tick(); - while(DHT20_get_status(i2c_sensor) == 0x80) { - if(furi_get_tick() - t > 10) return UT_SENSORSTATUS_TIMEOUT; - } - - if(!unitemp_i2c_readArray(i2c_sensor, 7, data)) return UT_SENSORSTATUS_TIMEOUT; - - if(DHT20_calc_CRC8(data, 6) != data[6]) { - return UT_SENSORSTATUS_BADCRC; - } - uint32_t RetuData = 0; - RetuData = (RetuData | data[1]) << 8; - RetuData = (RetuData | data[2]) << 8; - RetuData = (RetuData | data[3]); - RetuData = RetuData >> 4; - sensor->hum = RetuData * 100 * 10 / 1024.0f / 1024.0f / 10.0f; - - RetuData = 0; - RetuData = (RetuData | data[3]) << 8; - RetuData = (RetuData | data[4]) << 8; - RetuData = (RetuData | data[5]); - RetuData = RetuData & 0xfffff; - sensor->temp = (RetuData * 200 * 10.0f / 1024.0f / 1024.0f - 500) / 10.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/DHT20.h b/applications/external/unitemp/sensors/DHT20.h deleted file mode 100644 index 417b0ed1d..000000000 --- a/applications/external/unitemp/sensors/DHT20.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_DHT20 -#define UNITEMP_DHT20 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType DHT20; -extern const SensorType AHT10; -/** - * @brief Выделение памяти и установка начальных значений датчика DHT20 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика DHT20 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_DHT20_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_DHT20_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_DHT20_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/HDC1080.c b/applications/external/unitemp/sensors/HDC1080.c deleted file mode 100644 index 5f2c59b24..000000000 --- a/applications/external/unitemp/sensors/HDC1080.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "HDC1080.h" -#include "../interfaces/I2CSensor.h" - -const SensorType HDC1080 = { - .typename = "HDC1080", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 250, - .allocator = unitemp_HDC1080_alloc, - .mem_releaser = unitemp_HDC1080_free, - .initializer = unitemp_HDC1080_init, - .deinitializer = unitemp_HDC1080_deinit, - .updater = unitemp_HDC1080_update}; - -bool unitemp_HDC1080_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x40 << 1; - i2c_sensor->maxI2CAdr = 0x40 << 1; - return true; -} - -bool unitemp_HDC1080_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_HDC1080_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[2]; - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFF, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - uint16_t device_id = ((uint16_t)data[0] << 8) | data[1]; - if(device_id != 0x1050) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x1050", - sensor->name, - device_id); - return false; - } - data[0] = 0b0001000; - data[1] = 0; - //Установка режима работы и разрядности измерений - if(!unitemp_i2c_writeRegArray(i2c_sensor, 0x02, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - - return true; -} - -bool unitemp_HDC1080_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - UNUSED(i2c_sensor); - return true; -} - -UnitempStatus unitemp_HDC1080_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[2] = {0}; - //Запуск измерения - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(10); - if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - - sensor->temp = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 165 - 40; - - data[0] = 1; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(10); - if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - sensor->hum = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 100; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/HDC1080.h b/applications/external/unitemp/sensors/HDC1080.h deleted file mode 100644 index 59ba0673c..000000000 --- a/applications/external/unitemp/sensors/HDC1080.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_HDC1080 -#define UNITEMP_HDC1080 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType HDC1080; -/** - * @brief Выделение памяти и установка начальных значений датчика HDC1080 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_HDC1080_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика HDC1080 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_HDC1080_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HDC1080_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_HDC1080_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HDC1080_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/HTU21x.c b/applications/external/unitemp/sensors/HTU21x.c deleted file mode 100644 index 2e7222bc4..000000000 --- a/applications/external/unitemp/sensors/HTU21x.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "HTU21x.h" -#include "../interfaces/I2CSensor.h" - -const SensorType HTU21x = { - .typename = "HTU21x", - .altname = "HTU21x/SI70xx/SHT2x", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 250, - .allocator = unitemp_HTU21x_alloc, - .mem_releaser = unitemp_HTU21x_free, - .initializer = unitemp_HTU21x_init, - .deinitializer = unitemp_HTU21x_deinit, - .updater = unitemp_HTU21x_update}; - -static uint8_t checkCRC(uint16_t data) { - for(uint8_t i = 0; i < 16; i++) { - if(data & 0x8000) - data = (data << 1) ^ 0x13100; - else - data <<= 1; - } - return (data >> 8); -} - -bool unitemp_HTU21x_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x40 << 1; - i2c_sensor->maxI2CAdr = 0x41 << 1; - return true; -} - -bool unitemp_HTU21x_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_HTU21x_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - UNUSED(i2c_sensor); - return true; -} - -bool unitemp_HTU21x_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - UNUSED(i2c_sensor); - return true; -} - -UnitempStatus unitemp_HTU21x_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Датчик может быть всего один, так что норм - static bool temp_hum = false; - - uint8_t data[3]; - - if(sensor->status == UT_SENSORSTATUS_POLLING) { - if(!unitemp_i2c_readArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - - uint16_t raw = ((uint16_t)data[0] << 8) | data[1]; - if(checkCRC(raw) != data[2]) return UT_SENSORSTATUS_BADCRC; - - if(temp_hum) { - sensor->temp = (0.002681f * raw - 46.85f); - } else { - sensor->hum = ((0.001907 * (raw ^ 0x02)) - 6); - } - temp_hum = !temp_hum; - if(temp_hum) return UT_SENSORSTATUS_EARLYPOOL; - return UT_SENSORSTATUS_OK; - } - - if(temp_hum) { - //Запрос температуры - data[0] = 0xF3; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - } else { - //Запрос влажности - data[0] = 0xF5; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - } - - return UT_SENSORSTATUS_POLLING; -} diff --git a/applications/external/unitemp/sensors/HTU21x.h b/applications/external/unitemp/sensors/HTU21x.h deleted file mode 100644 index ffe062a24..000000000 --- a/applications/external/unitemp/sensors/HTU21x.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_HTU21x -#define UNITEMP_HTU21x - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType HTU21x; -/** - * @brief Выделение памяти и установка начальных значений датчика HTU21x - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_HTU21x_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика HTU21x - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_HTU21x_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HTU21x_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_HTU21x_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HTU21x_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/LM75.c b/applications/external/unitemp/sensors/LM75.c deleted file mode 100644 index a9c8df84e..000000000 --- a/applications/external/unitemp/sensors/LM75.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "LM75.h" -#include "../interfaces/I2CSensor.h" - -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONFIG 0x01 -#define LM75_REG_THYST 0x02 -#define LM75_REG_TOS 0x03 - -#define LM75_CONFIG_SHUTDOWN 0b00000001 -#define LM75_CONFIG_INTERRUPT 0b00000010 -#define LM75_CONFIG_OSPOLARITY_HIGH 0b00000100 -#define LM75_CONFIG_FAULTQUEUE_1 0b00000000 -#define LM75_CONFIG_FAULTQUEUE_2 0b00001000 -#define LM75_CONFIG_FAULTQUEUE_4 0b00010000 -#define LM75_CONFIG_FAULTQUEUE_6 0b00011000 - -const SensorType LM75 = { - .typename = "LM75", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP, - .pollingInterval = 500, - .allocator = unitemp_LM75_alloc, - .mem_releaser = unitemp_LM75_free, - .initializer = unitemp_LM75_init, - .deinitializer = unitemp_LM75_deinit, - .updater = unitemp_LM75_update}; - -bool unitemp_LM75_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0b1001000 << 1; - i2c_sensor->maxI2CAdr = 0b1001111 << 1; - return true; -} - -bool unitemp_LM75_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_LM75_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Выход если не удалось записать значение в датчик - if(!unitemp_i2c_writeReg(i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1)) return false; - - return true; -} - -bool unitemp_LM75_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_writeReg( - i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1 | LM75_CONFIG_SHUTDOWN)) - return false; - return true; -} - -UnitempStatus unitemp_LM75_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t buff[2]; - if(!unitemp_i2c_readRegArray(i2c_sensor, LM75_REG_TEMP, 2, buff)) - return UT_SENSORSTATUS_TIMEOUT; - int16_t raw = (((uint16_t)buff[0] << 8) | buff[1]); - sensor->temp = raw / 32 * 0.125; - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/LM75.h b/applications/external/unitemp/sensors/LM75.h deleted file mode 100644 index d5397b178..000000000 --- a/applications/external/unitemp/sensors/LM75.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_LM75 -#define UNITEMP_LM75 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType LM75; -/** - * @brief Выделение памяти и установка начальных значений датчика LM75 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_LM75_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика LM75 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_LM75_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_LM75_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_LM75_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_LM75_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/MAX31855.c b/applications/external/unitemp/sensors/MAX31855.c deleted file mode 100644 index 2411eb09e..000000000 --- a/applications/external/unitemp/sensors/MAX31855.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "MAX31855.h" - -const SensorType MAX31855 = { - .typename = "MAX31855", - .altname = "MAX31855 (Thermocouple)", - .interface = &SPI, - .datatype = UT_TEMPERATURE, - .pollingInterval = 500, - .allocator = unitemp_MAX31855_alloc, - .mem_releaser = unitemp_MAX31855_free, - .initializer = unitemp_MAX31855_init, - .deinitializer = unitemp_MAX31855_deinit, - .updater = unitemp_MAX31855_update}; - -bool unitemp_MAX31855_alloc(Sensor* sensor, char* args) { - UNUSED(sensor); - UNUSED(args); - return true; -} - -bool unitemp_MAX31855_free(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_MAX31855_init(Sensor* sensor) { - SPISensor* instance = sensor->instance; - furi_hal_spi_bus_handle_init(instance->spi); - UNUSED(instance); - return true; -} - -bool unitemp_MAX31855_deinit(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_MAX31855_update(Sensor* sensor) { - SPISensor* instance = sensor->instance; - - furi_hal_spi_acquire(instance->spi); - furi_hal_gpio_write(instance->CS_pin->pin, false); - - uint8_t buff[4] = {0}; - - furi_hal_spi_bus_rx(instance->spi, buff, 4, 0xFF); - furi_hal_spi_release(instance->spi); - - uint32_t raw = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3]; - - if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; - - //Определение состояния термопары - uint8_t state = raw & 0b111; - //Обрыв - if(state == 0x01) { - UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - //Короткое замыкание к земле - if(state == 0x02) { - UNITEMP_DEBUG("%s has thermocouple short to GND", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - //Короткое замыкание к питанию - if(state == 0x04) { - UNITEMP_DEBUG("%s has thermocouple short to VCC", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - raw = (raw >> 16) & 0xFFFC; - - sensor->temp = (int16_t)(raw) / 16.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/MAX31855.h b/applications/external/unitemp/sensors/MAX31855.h deleted file mode 100644 index d63c39885..000000000 --- a/applications/external/unitemp/sensors/MAX31855.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_MAX31855 -#define UNITEMP_MAX31855 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/SPISensor.h" - -extern const SensorType MAX31855; - -/** - * @brief Выделение памяти и установка начальных значений датчика MAX31855 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_MAX31855_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика MAX31855 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_MAX31855_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX31855_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_MAX31855_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX31855_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/MAX6675.c b/applications/external/unitemp/sensors/MAX6675.c deleted file mode 100644 index e97a96eb5..000000000 --- a/applications/external/unitemp/sensors/MAX6675.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "MAX6675.h" - -const SensorType MAX6675 = { - .typename = "MAX6675", - .altname = "MAX6675 (Thermocouple)", - .interface = &SPI, - .datatype = UT_TEMPERATURE, - .pollingInterval = 500, - .allocator = unitemp_MAX6675_alloc, - .mem_releaser = unitemp_MAX6675_free, - .initializer = unitemp_MAX6675_init, - .deinitializer = unitemp_MAX6675_deinit, - .updater = unitemp_MAX6675_update}; - -bool unitemp_MAX6675_alloc(Sensor* sensor, char* args) { - UNUSED(sensor); - UNUSED(args); - return true; -} - -bool unitemp_MAX6675_free(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_MAX6675_init(Sensor* sensor) { - SPISensor* instance = sensor->instance; - furi_hal_spi_bus_handle_init(instance->spi); - UNUSED(instance); - return true; -} - -bool unitemp_MAX6675_deinit(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_MAX6675_update(Sensor* sensor) { - SPISensor* instance = sensor->instance; - - furi_hal_spi_acquire(instance->spi); - furi_hal_gpio_write(instance->CS_pin->pin, false); - - uint8_t buff[2] = {0}; - - furi_hal_spi_bus_rx(instance->spi, buff, 2, 0xFF); - furi_hal_spi_release(instance->spi); - - uint32_t raw = (buff[0] << 8) | buff[1]; - - if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; - - //Определение состояния термопары - uint8_t state = raw & 0b100; - //Обрыв - if(state == 0b100) { - UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - sensor->temp = (int16_t)(raw) / 32.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/MAX6675.h b/applications/external/unitemp/sensors/MAX6675.h deleted file mode 100644 index cce346590..000000000 --- a/applications/external/unitemp/sensors/MAX6675.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_MAX6675 -#define UNITEMP_MAX6675 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/SPISensor.h" - -extern const SensorType MAX6675; - -/** - * @brief Выделение памяти и установка начальных значений датчика MAX6675 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_MAX6675_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика MAX6675 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_MAX6675_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX6675_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_MAX6675_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX6675_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD30.c b/applications/external/unitemp/sensors/SCD30.c deleted file mode 100644 index d7c358055..000000000 --- a/applications/external/unitemp/sensors/SCD30.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library - -#include "SCD30.h" -#include "../interfaces/I2CSensor.h" -#include "../interfaces/endianness.h" -//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h> - -typedef union { - uint16_t array16[2]; - uint8_t array8[4]; - float value; -} ByteToFl; - -const SensorType SCD30 = { - .typename = "SCD30", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM_CO2, - .pollingInterval = 2000, - .allocator = unitemp_SCD30_alloc, - .mem_releaser = unitemp_SCD30_free, - .initializer = unitemp_SCD30_init, - .deinitializer = unitemp_SCD30_deinit, - .updater = unitemp_SCD30_update}; - -#define SCD30_ID 0x61 - -#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010 -#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600 -#define COMMAND_GET_DATA_READY 0x0202 -#define COMMAND_READ_MEASUREMENT 0x0300 -#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306 -#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204 -#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403 -#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102 -#define COMMAND_RESET 0xD304 // Soft reset -#define COMMAND_STOP_MEAS 0x0104 -#define COMMAND_READ_FW_VER 0xD100 - -static bool dataAvailable(Sensor* sensor) __attribute__((unused)); -static bool readMeasurement(Sensor* sensor) __attribute__((unused)); -static void reset(Sensor* sensor) __attribute__((unused)); - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused)); -static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused)); - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused)); - -static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) - __attribute__((unused)); -static uint16_t getAltitudeCompensation(Sensor* sensor) __attribute__((unused)); -static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) __attribute__((unused)); -static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) __attribute__((unused)); - -static float getTemperatureOffset(Sensor* sensor) __attribute__((unused)); -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused)); - -static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) - __attribute__((unused)); -static bool beginMeasuring(Sensor* sensor) __attribute__((unused)); -static bool stopMeasurement(Sensor* sensor) __attribute__((unused)); - -static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) __attribute__((unused)); -static uint16_t getMeasurementInterval(Sensor* sensor) __attribute__((unused)); - -bool unitemp_SCD30_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - i2c_sensor->minI2CAdr = SCD30_ID << 1; - i2c_sensor->maxI2CAdr = SCD30_ID << 1; - return true; -} - -bool unitemp_SCD30_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SCD30_init(Sensor* sensor) { - if(beginMeasuring(sensor) == true) { // Start continuous measurements - setMeasurementInterval(sensor, SCD30.pollingInterval / 1000); - setAutoSelfCalibration(sensor, true); - setAmbientPressure(sensor, 0); - } else - return false; - - return true; -} - -bool unitemp_SCD30_deinit(Sensor* sensor) { - return stopMeasurement(sensor); -} - -UnitempStatus unitemp_SCD30_update(Sensor* sensor) { - readMeasurement(sensor); - return UT_SENSORSTATUS_OK; -} - -static uint8_t computeCRC8(uint8_t* message, uint8_t len) { - uint8_t crc = 0xFF; // Init with 0xFF - for(uint8_t x = 0; x < len; x++) { - crc ^= message[x]; // XOR-in the next input byte - for(uint8_t i = 0; i < 8; i++) { - if((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ 0x31); - else - crc <<= 1; - } - } - return crc; // No output reflection -} - -// Sends a command along with arguments and CRC -static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) { - static const uint8_t cmdSize = 5; - - uint8_t bytes[cmdSize]; - uint8_t* pointer = bytes; - store16_be(pointer, command); - pointer += 2; - uint8_t* argPos = pointer; - store16_be(pointer, arguments); - pointer += 2; - *pointer = computeCRC8(argPos, pointer - argPos); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -// Sends just a command, no arguments, no CRC -static bool sendCommand(Sensor* sensor, uint16_t command) { - static const uint8_t cmdSize = 2; - - uint8_t bytes[cmdSize]; - store16_be(bytes, command); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) { - static const uint8_t regSize = 2; - - if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[regSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0; - - return load16_be(bytes); -} - -static bool loadWord(uint8_t* buff, uint16_t* val) { - uint16_t tmp = load16_be(buff); - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - *val = tmp; - return true; -} - -static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) { - static const uint8_t respSize = 3; - - if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[respSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false; - - return loadWord(bytes, val); -} - -static bool loadFloat(uint8_t* buff, float* val) { - // ByteToFl tmp; - size_t cntr = 0; - uint8_t floatBuff[4]; - for(size_t i = 0; i < 2; i++) { - floatBuff[cntr++] = buff[0]; - floatBuff[cntr++] = buff[1]; - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - buff += 3; - } - uint32_t tmpVal = load32_be(floatBuff); - memcpy(val, &tmpVal, sizeof(float)); - return true; -} - -// Get 18 bytes from SCD30 -// Updates global variables with floats -// Returns true if success -static bool readMeasurement(Sensor* sensor) { - // Verify we have data from the sensor - if(!dataAvailable(sensor)) { - return false; - } - - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - float tempCO2 = 0; - float tempHumidity = 0; - float tempTemperature = 0; - - furi_delay_ms(3); - - static const uint8_t respSize = 18; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - bool error = false; - if(loadFloat(bytes, &tempCO2)) { - sensor->co2 = tempCO2; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing CO2"); - error = true; - } - - bytes += 6; - if(loadFloat(bytes, &tempTemperature)) { - sensor->temp = tempTemperature; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing temp"); - error = true; - } - - bytes += 6; - if(loadFloat(bytes, &tempHumidity)) { - sensor->hum = tempHumidity; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing humidity"); - error = true; - } - - return !error; -} - -static void reset(Sensor* sensor) { - sendCommand(sensor, COMMAND_RESET); -} - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) { - return sendCommandWithCRC( - sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION, enable); // Activate continuous ASC -} - -// Get the current ASC setting -static bool getAutoSelfCalibration(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION); -} - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) { - return getSettingValue(sensor, COMMAND_READ_FW_VER, val); -} - -// Set the forced recalibration factor. See 1.3.7. -// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm. -static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) { - if(concentration < 400 || concentration > 2000) { - return false; // Error check. - } - return sendCommandWithCRC(sensor, COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration); -} - -// Get the temperature offset. See 1.3.8. -static float getTemperatureOffset(Sensor* sensor) { - union { - int16_t signed16; - uint16_t unsigned16; - } signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t - signedUnsigned.unsigned16 = readRegister(sensor, COMMAND_SET_TEMPERATURE_OFFSET); - - return ((float)signedUnsigned.signed16) / 100.0; -} - -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) { - // Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826 - //"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature" - // https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf - - if(tempOffset < 0.0) return false; - - uint16_t value = tempOffset * 100; - - return sendCommandWithCRC(sensor, COMMAND_SET_TEMPERATURE_OFFSET, value); -} - -// Get the altitude compenstation. See 1.3.9. -static uint16_t getAltitudeCompensation(Sensor* sensor) { - return readRegister(sensor, COMMAND_SET_ALTITUDE_COMPENSATION); -} - -// Set the altitude compenstation. See 1.3.9. -static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) { - return sendCommandWithCRC(sensor, COMMAND_SET_ALTITUDE_COMPENSATION, altitude); -} - -// Set the pressure compenstation. This is passed during measurement startup. -// mbar can be 700 to 1200 -static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) { - if(pressure_mbar != 0 || pressure_mbar < 700 || pressure_mbar > 1200) { - return false; - } - return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar); -} - -// Begins continuous measurements -// Continuous measurement status is saved in non-volatile memory. When the sensor -// is powered down while continuous measurement mode is active SCD30 will measure -// continuously after repowering without sending the measurement command. -// Returns true if successful -static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) { - return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset); -} - -// Overload - no pressureOffset -static bool beginMeasuring(Sensor* sensor) { - return beginMeasuringWithSettings(sensor, 0); -} - -// Stop continuous measurement -static bool stopMeasurement(Sensor* sensor) { - return sendCommand(sensor, COMMAND_STOP_MEAS); -} - -// Sets interval between measurements -// 2 seconds to 1800 seconds (30 minutes) -static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) { - if(interval < 2 || interval > 1800) return false; - if(!sendCommandWithCRC(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, interval)) return false; - uint16_t verInterval = readRegister(sensor, COMMAND_SET_MEASUREMENT_INTERVAL); - if(verInterval != interval) { - FURI_LOG_E(APP_NAME, "Measure interval wrong! Val: %02x", verInterval); - return false; - } - return true; -} - -// Gets interval between measurements -// 2 seconds to 1800 seconds (30 minutes) -static uint16_t getMeasurementInterval(Sensor* sensor) { - uint16_t interval = 0; - getSettingValue(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, &interval); - return interval; -} - -// Returns true when data is available -static bool dataAvailable(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_GET_DATA_READY); -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD30.h b/applications/external/unitemp/sensors/SCD30.h deleted file mode 100644 index 1ebfbb411..000000000 --- a/applications/external/unitemp/sensors/SCD30.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCD30 -#define UNITEMP_SCD30 - -#include "../unitemp.h" -#include "../Sensors.h" - -extern const SensorType SCD30; -/** - * @brief Выделение памяти и установка начальных значений датчика SCD30 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SCD30_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SCD30 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SCD30_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD30_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_SCD30_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD30_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD40.c b/applications/external/unitemp/sensors/SCD40.c deleted file mode 100644 index 75c5a3f56..000000000 --- a/applications/external/unitemp/sensors/SCD40.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library - -#include "SCD40.h" -#include "../interfaces/I2CSensor.h" -#include "../interfaces/endianness.h" -//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h> - -const SensorType SCD40 = { - .typename = "SCD40", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM_CO2, - .pollingInterval = 5000, - .allocator = unitemp_SCD40_alloc, - .mem_releaser = unitemp_SCD40_free, - .initializer = unitemp_SCD40_init, - .deinitializer = unitemp_SCD40_deinit, - .updater = unitemp_SCD40_update}; - -#define SCD40_ID 0x62 - -#define COMMAND_START_PERIODIC_MEASUREMENT 0X21B1 -#define COMMAND_READ_MEASUREMENT 0XEC05 -#define COMMAND_STOP_PERIODIC_MEASUREMENT 0X3F86 - -#define COMMAND_PERSIST_SETTINGS 0X3615 -#define COMMAND_GET_SERIAL_NUMBER 0X3682 -#define COMMAND_PERFORM_SELF_TEST 0X3639 -#define COMMAND_PERFORM_FACTORY_RESET 0X3632 -#define COMMAND_REINIT 0X3646 - -#define COMMAND_SET_TEMPERATURE_OFFSET 0X241D -#define COMMAND_GET_TEMPERATURE_OFFSET 0X2318 -#define COMMAND_SET_SENSOR_ALTITUDE 0X2427 -#define COMMAND_GET_SENSOR_ALTITUDE 0X2322 -#define COMMAND_SET_AMBIENT_PRESSURE 0XE000 -#define COMMAND_PERFORM_FORCED_RECALIBRATION 0X362F -#define COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED 0X2416 -#define COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED 0X2313 - -static bool readMeasurement(Sensor* sensor) __attribute__((unused)); -static void reset(Sensor* sensor) __attribute__((unused)); - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused)); -static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused)); - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused)); - -static float getTemperatureOffset(Sensor* sensor) __attribute__((unused)); -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused)); - -static bool beginMeasuring(Sensor* sensor) __attribute__((unused)); -static bool stopMeasurement(Sensor* sensor) __attribute__((unused)); - -bool unitemp_SCD40_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - i2c_sensor->minI2CAdr = SCD40_ID << 1; - i2c_sensor->maxI2CAdr = SCD40_ID << 1; - return true; -} - -bool unitemp_SCD40_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SCD40_init(Sensor* sensor) { - return beginMeasuring(sensor); -} - -bool unitemp_SCD40_deinit(Sensor* sensor) { - return stopMeasurement(sensor); -} - -UnitempStatus unitemp_SCD40_update(Sensor* sensor) { - readMeasurement(sensor); - return UT_SENSORSTATUS_OK; -} - -#define CRC8_POLYNOMIAL 0x31 -#define CRC8_INIT 0xFF - -static uint8_t computeCRC8(uint8_t* message, uint8_t len) { - uint8_t crc = CRC8_INIT; // Init with 0xFF - for(uint8_t x = 0; x < len; x++) { - crc ^= message[x]; // XOR-in the next input byte - for(uint8_t i = 0; i < 8; i++) { - if((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ CRC8_POLYNOMIAL); - else - crc <<= 1; - } - } - return crc; // No output reflection -} - -// Sends a command along with arguments and CRC -static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) { - static const uint8_t cmdSize = 5; - - uint8_t bytes[cmdSize]; - uint8_t* pointer = bytes; - store16_be(pointer, command); - pointer += 2; - uint8_t* argPos = pointer; - store16_be(pointer, arguments); - pointer += 2; - *pointer = computeCRC8(argPos, pointer - argPos); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -// Sends just a command, no arguments, no CRC -static bool sendCommand(Sensor* sensor, uint16_t command) { - static const uint8_t cmdSize = 2; - - uint8_t bytes[cmdSize]; - store16_be(bytes, command); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) { - static const uint8_t regSize = 2; - - if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[regSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0; - - return load16_be(bytes); -} - -static bool loadWord(uint8_t* buff, uint16_t* val) { - uint16_t tmp = load16_be(buff); - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - *val = tmp; - return true; -} - -static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) { - static const uint8_t respSize = 3; - - if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[respSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false; - - return loadWord(bytes, val); -} - -// Get 18 bytes from SCD40 -// Updates global variables with floats -// Returns true if success -static bool readMeasurement(Sensor* sensor) { - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - furi_delay_ms(3); - - static const uint8_t respSize = 9; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - uint16_t tmpValue; - - bool error = false; - if(loadWord(bytes, &tmpValue)) { - sensor->co2 = tmpValue; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing CO2"); - error = true; - } - - bytes += 3; - if(loadWord(bytes, &tmpValue)) { - sensor->temp = (float)tmpValue * 175.0f / 65535.0f - 45.0f; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing temp"); - error = true; - } - - bytes += 3; - if(loadWord(bytes, &tmpValue)) { - sensor->hum = (float)tmpValue * 100.0f / 65535.0f; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing humidity"); - error = true; - } - - return !error; -} - -static void reset(Sensor* sensor) { - sendCommand(sensor, COMMAND_REINIT); -} - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) { - return sendCommandWithCRC( - sensor, COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED, enable); // Activate continuous ASC -} - -// Get the current ASC setting -static bool getAutoSelfCalibration(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED); -} - -// Unfinished -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) { - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - static const uint8_t respSize = 9; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - *val = 0; - - return true; -} - -static bool beginMeasuring(Sensor* sensor) { - return sendCommand(sensor, COMMAND_START_PERIODIC_MEASUREMENT); -} - -// Stop continuous measurement -static bool stopMeasurement(Sensor* sensor) { - return sendCommand(sensor, COMMAND_READ_MEASUREMENT); -} - -static float getTemperatureOffset(Sensor* sensor) { - uint16_t curOffset; - if(!getSettingValue(sensor, COMMAND_GET_TEMPERATURE_OFFSET, &curOffset)) return 0.0; - return (float)curOffset * 175.0f / 65536.0f; -} - -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) { - uint16_t newOffset = tempOffset * 65536.0 / 175.0 + 0.5f; - return sendCommandWithCRC( - sensor, COMMAND_SET_TEMPERATURE_OFFSET, newOffset); // Activate continuous ASC -} diff --git a/applications/external/unitemp/sensors/SCD40.h b/applications/external/unitemp/sensors/SCD40.h deleted file mode 100644 index 5cf7a4324..000000000 --- a/applications/external/unitemp/sensors/SCD40.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCD40 -#define UNITEMP_SCD40 - -#include "../unitemp.h" -#include "../Sensors.h" - -extern const SensorType SCD40; -/** - * @brief Выделение памяти и установка начальных значений датчика SCD40 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SCD40_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SCD40 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SCD40_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD40_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_SCD40_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD40_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SHT30.c b/applications/external/unitemp/sensors/SHT30.c deleted file mode 100644 index dd43e80af..000000000 --- a/applications/external/unitemp/sensors/SHT30.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "SHT30.h" -#include "../interfaces/I2CSensor.h" - -const SensorType SHT30 = { - .typename = "SHT30", - .altname = "SHT30/31/35", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_SHT30_I2C_alloc, - .mem_releaser = unitemp_SHT30_I2C_free, - .initializer = unitemp_SHT30_init, - .deinitializer = unitemp_SHT30_I2C_deinit, - .updater = unitemp_SHT30_I2C_update}; -const SensorType GXHT30 = { - .typename = "GXHT30", - .altname = "GXHT30/31/35", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_SHT30_I2C_alloc, - .mem_releaser = unitemp_SHT30_I2C_free, - .initializer = unitemp_GXHT30_init, - .deinitializer = unitemp_SHT30_I2C_deinit, - .updater = unitemp_SHT30_I2C_update}; - -bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x44 << 1; - i2c_sensor->maxI2CAdr = 0x45 << 1; - return true; -} - -bool unitemp_SHT30_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SHT30_init(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_GXHT30_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Включение режима автоматического преобразования 2 раза в сек - uint8_t data[2] = {0x22, 0x36}; - if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return false; - return true; -} - -bool unitemp_SHT30_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Получение данных - uint8_t data[6] = {0xE0, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_i2c_readArray(i2c_sensor, 6, data)) return UT_SENSORSTATUS_TIMEOUT; - - sensor->temp = -45 + 175 * (((uint16_t)(data[0] << 8) | data[1]) / 65535.0f); - sensor->hum = 100 * (((uint16_t)(data[3] << 8) | data[4]) / 65535.0f); - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/SHT30.h b/applications/external/unitemp/sensors/SHT30.h deleted file mode 100644 index 4b5b74411..000000000 --- a/applications/external/unitemp/sensors/SHT30.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SHT30 -#define UNITEMP_SHT30 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType SHT30; -extern const SensorType GXHT30; -/** - * @brief Выделение памяти и установка начальных значений датчика SHT30 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SHT30 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SHT30_init(Sensor* sensor); -/** - * @brief Инициализации датчика GXHT30 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_GXHT30_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_SHT30_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_SHT30_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/Sensors.xlsx b/applications/external/unitemp/sensors/Sensors.xlsx deleted file mode 100644 index c314098a8..000000000 Binary files a/applications/external/unitemp/sensors/Sensors.xlsx and /dev/null differ diff --git a/applications/external/unitemp/unitemp.c b/applications/external/unitemp/unitemp.c deleted file mode 100644 index 9f56d8eef..000000000 --- a/applications/external/unitemp/unitemp.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "unitemp.h" -#include "interfaces/SingleWireSensor.h" -#include "Sensors.h" -#include "./views/UnitempViews.h" - -#include - -/* Переменные */ -//Данные приложения -Unitemp* app; - -void uintemp_celsiumToFarengate(Sensor* sensor) { - sensor->temp = sensor->temp * (9.0 / 5.0) + 32; - sensor->heat_index = sensor->heat_index * (9.0 / 5.0) + 32; -} - -static float heat_index_consts[9] = { - -42.379f, - 2.04901523f, - 10.14333127f, - -0.22475541f, - -0.00683783f, - -0.05481717f, - 0.00122874f, - 0.00085282f, - -0.00000199f}; -void unitemp_calculate_heat_index(Sensor* sensor) { - // temp should be in Celsius, heat index will be in Celsius - float temp = sensor->temp * (9.0 / 5.0) + 32.0f; - float hum = sensor->hum; - sensor->heat_index = - (heat_index_consts[0] + heat_index_consts[1] * temp + heat_index_consts[2] * hum + - heat_index_consts[3] * temp * hum + heat_index_consts[4] * temp * temp + - heat_index_consts[5] * hum * hum + heat_index_consts[6] * temp * temp * hum + - heat_index_consts[7] * temp * hum * hum + heat_index_consts[8] * temp * temp * hum * hum - - 32.0f) * - (5.0 / 9.0); -} -void unitemp_pascalToMmHg(Sensor* sensor) { - sensor->pressure = sensor->pressure * 0.007500638; -} -void unitemp_pascalToKPa(Sensor* sensor) { - sensor->pressure = sensor->pressure / 1000.0f; -} -void unitemp_pascalToHPa(Sensor* sensor) { - sensor->pressure = sensor->pressure / 100.0f; -} -void unitemp_pascalToInHg(Sensor* sensor) { - sensor->pressure = sensor->pressure * 0.0002953007; -} - -bool unitemp_saveSettings(void) { - //Выделение памяти для потока - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS); - //Создание папки плагина - storage_common_mkdir(app->storage, APP_PATH_FOLDER); - //Открытие потока - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { - FURI_LOG_E( - APP_NAME, - "An error occurred while saving the settings file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - - //Сохранение настроек - stream_write_format( - app->file_stream, "INFINITY_BACKLIGHT %d\n", app->settings.infinityBacklight); - stream_write_format(app->file_stream, "TEMP_UNIT %d\n", app->settings.temp_unit); - stream_write_format(app->file_stream, "PRESSURE_UNIT %d\n", app->settings.pressure_unit); - stream_write_format(app->file_stream, "HEAT_INDEX %d\n", app->settings.heat_index); - - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Settings have been successfully saved"); - return true; -} - -bool unitemp_loadSettings(void) { - UNITEMP_DEBUG("Loading settings..."); - - //Выделение памяти на поток - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS); - - //Открытие потока к файлу настроек - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { - //Сохранение настроек по умолчанию в случае отсутствия файла - if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) { - FURI_LOG_W(APP_NAME, "Missing settings file. Setting defaults and saving..."); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - //Сохранение стандартного конфига - unitemp_saveSettings(); - return false; - } else { - FURI_LOG_E( - APP_NAME, - "An error occurred while loading the settings file: %d. Standard values have been applied", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - } - - //Вычисление размера файла - uint8_t file_size = stream_size(app->file_stream); - //Если файл пустой, то: - if(file_size == (uint8_t)0) { - FURI_LOG_W(APP_NAME, "Settings file is empty"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - //Сохранение стандартного конфига - unitemp_saveSettings(); - return false; - } - //Выделение памяти под загрузку файла - uint8_t* file_buf = malloc(file_size); - //Опустошение буфера файла - memset(file_buf, 0, file_size); - //Загрузка файла - if(stream_read(app->file_stream, file_buf, file_size) != file_size) { - //Выход при ошибке чтения - FURI_LOG_E(APP_NAME, "Error reading settings file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - free(file_buf); - return false; - } - //Построчное чтение файла - //Указатель на начало строки - FuriString* file = furi_string_alloc_set_str((char*)file_buf); - //Сколько байт до конца строки - size_t line_end = 0; - - while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { - char buff[20] = {0}; - sscanf(((char*)(file_buf + line_end)), "%s", buff); - - if(!strcmp(buff, "INFINITY_BACKLIGHT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "INFINITY_BACKLIGHT %d", &p); - app->settings.infinityBacklight = p; - } else if(!strcmp(buff, "TEMP_UNIT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nTEMP_UNIT %d", &p); - app->settings.temp_unit = p; - } else if(!strcmp(buff, "PRESSURE_UNIT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nPRESSURE_UNIT %d", &p); - app->settings.pressure_unit = p; - } else if(!strcmp(buff, "HEAT_INDEX")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nHEAT_INDEX %d", &p); - app->settings.heat_index = p; - } else { - FURI_LOG_W(APP_NAME, "Unknown settings parameter: %s", buff); - } - - //Вычисление конца строки - line_end = furi_string_search_char(file, '\n', line_end + 1); - } - free(file_buf); - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Settings have been successfully loaded"); - return true; -} - -/** - * @brief Выделение места под переменные плагина - * - * @return true Если всё прошло успешно - * @return false Если в процессе загрузки произошла ошибка - */ -static bool unitemp_alloc(void) { - //Выделение памяти под данные приложения - app = malloc(sizeof(Unitemp)); - //Разрешение работы приложения - app->processing = true; - - //Открытие хранилища (?) - app->storage = furi_record_open(RECORD_STORAGE); - storage_common_migrate(app->storage, EXT_PATH("unitemp"), APP_PATH_FOLDER); - - //Уведомления - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - //Установка значений по умолчанию - app->settings.infinityBacklight = true; //Подсветка горит всегда - app->settings.temp_unit = UT_TEMP_CELSIUS; //Единица измерения температуры - градусы Цельсия - app->settings.pressure_unit = UT_PRESSURE_MM_HG; //Единица измерения давления - мм рт. ст. - app->settings.heat_index = false; - - app->gui = furi_record_open(RECORD_GUI); - //Диспетчер окон - app->view_dispatcher = view_dispatcher_alloc(); - - app->sensors = NULL; - - app->buff = malloc(BUFF_SIZE); - - unitemp_General_alloc(); - - unitemp_MainMenu_alloc(); - unitemp_Settings_alloc(); - unitemp_SensorsList_alloc(); - unitemp_SensorEdit_alloc(); - unitemp_SensorNameEdit_alloc(); - unitemp_SensorActions_alloc(); - unitemp_widgets_alloc(); - - //Всплывающее окно - app->popup = popup_alloc(); - view_dispatcher_add_view(app->view_dispatcher, UnitempViewPopup, popup_get_view(app->popup)); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - return true; -} - -/** - * @brief Освыбождение памяти после работы приложения - */ -static void unitemp_free(void) { - popup_free(app->popup); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewPopup); - unitemp_widgets_free(); - - unitemp_SensorActions_free(); - unitemp_SensorNameEdit_free(); - unitemp_SensorEdit_free(); - unitemp_SensorsList_free(); - unitemp_Settings_free(); - unitemp_MainMenu_free(); - unitemp_General_free(); - - free(app->buff); - - view_dispatcher_free(app->view_dispatcher); - furi_record_close(RECORD_GUI); - //Очистка датчиков - //Высвыбождение данных датчиков - unitemp_sensors_free(); - free(app->sensors); - - //Закрытие уведомлений - furi_record_close(RECORD_NOTIFICATION); - //Закрытие хранилища - furi_record_close(RECORD_STORAGE); - //Удаление в самую последнюю очередь - free(app); -} - -/** - * @brief Точка входа в приложение - * - * @return Код ошибки - */ -int32_t unitemp_app() { - //Выделение памяти под переменные - //Выход если произошла ошибка - if(unitemp_alloc() == false) { - //Освобождение памяти - unitemp_free(); - //Выход - return 0; - } - - //Загрузка настроек из SD-карты - unitemp_loadSettings(); - //Применение настроек - if(app->settings.infinityBacklight == true) { - //Постоянное свечение подсветки - notification_message(app->notifications, &sequence_display_backlight_enforce_on); - } - app->settings.lastOTGState = furi_hal_power_is_otg_enabled(); - //Загрузка датчиков из SD-карты - unitemp_sensors_load(); - //Инициализация датчиков - unitemp_sensors_init(); - - unitemp_General_switch(); - - while(app->processing) { - if(app->sensors_ready) unitemp_sensors_updateValues(); - furi_delay_ms(100); - } - - //Деинициализация датчиков - unitemp_sensors_deInit(); - //Автоматическое управление подсветкой - if(app->settings.infinityBacklight == true) - notification_message(app->notifications, &sequence_display_backlight_enforce_auto); - //Освобождение памяти - unitemp_free(); - //Выход - return 0; -} diff --git a/applications/external/unitemp/unitemp.h b/applications/external/unitemp/unitemp.h deleted file mode 100644 index 320163126..000000000 --- a/applications/external/unitemp/unitemp.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP -#define UNITEMP - -/* Подключение стандартных библиотек */ - -/* Подключение API Flipper Zero */ -//Файловый поток -#include -//Экран -#include -#include -#include -#include -//Уведомления -#include -#include - -/* Внутренние библиотеки */ -//Интерфейсы подключения датчиков -#include "Sensors.h" - -/* Объявление макроподстановок */ -//Имя приложения -#define APP_NAME "Unitemp" -//Версия приложения -#define UNITEMP_APP_VER "1.4" -//Путь хранения файлов плагина -#define APP_PATH_FOLDER EXT_PATH("apps_data/unitemp") -//Имя файла с настройками -#define APP_FILENAME_SETTINGS "settings.cfg" -//Имя файла с датчиками -#define APP_FILENAME_SENSORS "sensors.cfg" - -//Размер буффера текста -#define BUFF_SIZE 32 - -#define UNITEMP_D - -#ifdef FURI_DEBUG -#define UNITEMP_DEBUG(msg, ...) FURI_LOG_D(APP_NAME, msg, ##__VA_ARGS__) -#else -#define UNITEMP_DEBUG(msg, ...) -#endif - -/* Объявление перечислений */ -//Единицы измерения температуры -typedef enum { UT_TEMP_CELSIUS, UT_TEMP_FAHRENHEIT, UT_TEMP_COUNT } tempMeasureUnit; -//Единицы измерения давления -typedef enum { - UT_PRESSURE_MM_HG, - UT_PRESSURE_IN_HG, - UT_PRESSURE_KPA, - UT_PRESSURE_HPA, - - UT_PRESSURE_COUNT -} pressureMeasureUnit; -/* Объявление структур */ -//Настройки плагина -typedef struct { - //Бесконечная работа подсветки - bool infinityBacklight; - //Единица измерения температуры - tempMeasureUnit temp_unit; - //Единица измерения давления - pressureMeasureUnit pressure_unit; - // Do calculate and show heat index - bool heat_index; - //Последнее состояние OTG - bool lastOTGState; -} UnitempSettings; - -//Основная структура плагина -typedef struct { - //Система - bool processing; //Флаг работы приложения. При ложном значении приложение закрывается - bool sensors_ready; //Флаг готовности датчиков к опросу - //Основные настройки - UnitempSettings settings; - //Массив указателей на датчики - Sensor** sensors; - //Количество загруженных датчиков - uint8_t sensors_count; - //SD-карта - Storage* storage; //Хранилище - Stream* file_stream; //Файловый поток - - //Экран - Gui* gui; - ViewDispatcher* view_dispatcher; - NotificationApp* notifications; - Widget* widget; - Popup* popup; - //Буффер для различного текста - char* buff; -} Unitemp; - -/* Объявление прототипов функций */ - -/** - * @brief Calculates the heat index in Celsius from the temperature and humidity and stores it in the sensor heat_index field - * - * @param sensor The sensor struct, with temperature in Celcius and humidity in percent - */ -void unitemp_calculate_heat_index(Sensor* sensor); - -/** - * @brief Перевод значения температуры датчика из Цельсия в Фаренгейты - * - * @param sensor Указатель на датчик - */ -void uintemp_celsiumToFarengate(Sensor* sensor); - -/** - * @brief Конвертация давления из паскалей в мм рт.ст. - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToMmHg(Sensor* sensor); - -/** - * @brief Конвертация давления из паскалей в килопаскали - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToKPa(Sensor* sensor); -/** - * @brief Конвертация давления из паскалей в дюйм рт.ст. - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToHPa(Sensor* sensor); -/** - * - * Mod BySepa - linktr.ee/BySepa - * - */ -void unitemp_pascalToInHg(Sensor* sensor); - -/** - * @brief Сохранение настроек на SD-карту - * - * @return Истина если сохранение успешное - */ -bool unitemp_saveSettings(void); -/** - * @brief Загрузка настроек с SD-карты - * - * @return Истина если загрузка успешная - */ -bool unitemp_loadSettings(void); - -extern Unitemp* app; -#endif diff --git a/applications/external/unitemp/views/General_view.c b/applications/external/unitemp/views/General_view.c deleted file mode 100644 index d0d269126..000000000 --- a/applications/external/unitemp/views/General_view.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include "unitemp_icons.h" -#include - -// extern const Icon I_ButtonRight_4x7; -// extern const Icon I_ButtonLeft_4x7; -// extern const Icon I_Ok_btn_9x9; - -static View* view; - -typedef enum general_views { - G_NO_SENSORS_VIEW, //Нет датчиков - G_LIST_VIEW, //Вид в ввиде списка - G_CAROUSEL_VIEW, //Карусель -} general_view; - -typedef enum carousel_info { - CAROUSEL_VALUES, //Отображение значений датчиков - CAROUSEL_INFO, //Отображение информации о датчике -} carousel_info; - -static general_view current_view; - -carousel_info carousel_info_selector = CAROUSEL_VALUES; -uint8_t generalview_sensor_index = 0; - -static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t y, Color color) { - //Рисование рамки - canvas_draw_rframe(canvas, x, y, 54, 20, 3); - - if(color == ColorBlack) { - canvas_draw_rbox(canvas, x, y, 54, 19, 3); - canvas_invert_color(canvas); - } else { - canvas_draw_rframe(canvas, x, y, 54, 19, 3); - } - - int8_t temp_dec = abs((int16_t)(sensor->temp * 10) % 10); - - //Рисование иконки - canvas_draw_icon( - canvas, - x + 3, - y + 3, - (app->settings.temp_unit == UT_TEMP_CELSIUS ? &I_temp_C_11x14 : &I_temp_F_11x14)); - - if((int16_t)sensor->temp == -128 || sensor->status == UT_SENSORSTATUS_TIMEOUT) { - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, x + 27, y + 10, AlignCenter, AlignCenter, "--"); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, x + 50, y + 10 + 3, AlignRight, AlignCenter, ". -"); - if(color == ColorBlack) canvas_invert_color(canvas); - return; - } - - //Целая часть температуры - //Костыль для отображения знака числа меньше 0 - uint8_t offset = 0; - if(sensor->temp < 0 && sensor->temp > -1) { - app->buff[0] = '-'; - offset = 1; - } - snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int16_t)sensor->temp); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, - x + 27 + ((sensor->temp <= -10 || sensor->temp > 99) ? 5 : 0), - y + 10, - AlignCenter, - AlignCenter, - app->buff); - //Печать дробной части температуры в диапазоне от -9 до 99 (когда два знака в числе) - if(sensor->temp > -10 && sensor->temp <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", temp_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff); - } - if(color == ColorBlack) canvas_invert_color(canvas); -} - -static void _draw_humidity(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) { - //Рисование рамки - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3); - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3); - - //Рисование иконки - canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 2, &I_hum_9x15); - - //Целая часть влажности - snprintf(app->buff, BUFF_SIZE, "%d", (uint8_t)sensor->hum); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff); - uint8_t int_len = canvas_string_width(canvas, app->buff); - //Единица измерения - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 4, pos[1] + 10 + 7, "%"); -} - -static void _draw_heat_index(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) { - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3); - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3); - - canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 3, &I_heat_index_11x14); - - int16_t heat_index_int = sensor->heat_index; - int8_t heat_index_dec = abs((int16_t)(sensor->heat_index * 10) % 10); - - snprintf(app->buff, BUFF_SIZE, "%d", heat_index_int); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, - pos[0] + 27 + ((sensor->heat_index <= -10 || sensor->heat_index > 99) ? 5 : 0), - pos[1] + 10, - AlignCenter, - AlignCenter, - app->buff); - - if(heat_index_int <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", heat_index_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 2, pos[1] + 10 + 7, app->buff); - } -} - -static void _draw_pressure(Canvas* canvas, Sensor* sensor) { - const uint8_t x = 29, y = 39; - //Рисование рамки - if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - canvas_draw_rframe(canvas, x, y, 84, 20, 3); - canvas_draw_rframe(canvas, x, y, 84, 19, 3); - } else { - canvas_draw_rframe(canvas, x, y, 69, 20, 3); - canvas_draw_rframe(canvas, x, y, 69, 19, 3); - } - - //Рисование иконки - canvas_draw_icon(canvas, x + 3, y + 4, &I_pressure_7x13); - - int16_t press_int = sensor->pressure; - // Change Temp for Pressure - int8_t press_dec = (int16_t)(sensor->pressure * 10) % 10; - - //Целая часть давления - snprintf(app->buff, BUFF_SIZE, "%d", press_int); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, x + 27 + ((press_int > 99) ? 5 : 0), y + 10, AlignCenter, AlignCenter, app->buff); - //Печать дробной части давления в диапазоне от 0 до 99 (когда два знака в числе) - if(press_int <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", press_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff); - } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", press_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 32 + int_len / 2 + 2, y + 10 + 7, app->buff); - } - canvas_set_font(canvas, FontSecondary); - //Единица измерения - - if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) { - canvas_draw_icon(canvas, x + 50, y + 2, &I_mm_hg_15x15); - } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) { - canvas_draw_icon(canvas, x + 50, y + 2, &I_in_hg_15x15); - } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) { - canvas_draw_str(canvas, x + 52, y + 13, "kPa"); - } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - canvas_draw_str(canvas, x + 67, y + 13, "hPa"); - } -} - -static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) { - const uint8_t x = 29, y = 39; - //Рисование рамки - canvas_draw_rframe(canvas, x, y, 75, 20, 3); - if(color == ColorBlack) { - canvas_draw_rbox(canvas, x, y, 75, 19, 3); - canvas_invert_color(canvas); - } else { - canvas_draw_rframe(canvas, x, y, 75, 19, 3); - } - - //Рисование иконки - canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14); - - int16_t concentration_int = sensor->co2; - // int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10; - - //Целая часть - if(concentration_int > 9999) { - snprintf(app->buff, BUFF_SIZE, "MAX "); - canvas_set_font(canvas, FontPrimary); - } else { - snprintf(app->buff, BUFF_SIZE, "%d", concentration_int); - canvas_set_font(canvas, FontBigNumbers); - } - - canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff); -} - -static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) { - canvas_set_font(canvas, FontPrimary); - - const uint8_t max_width = 56; - - char sensor_name[12] = {0}; - memcpy(sensor_name, sensor->name, 10); - - if(canvas_string_width(canvas, sensor_name) > max_width) { - uint8_t i = 10; - while((canvas_string_width(canvas, sensor_name) > max_width - 6) && (i != 0)) { - sensor_name[i--] = '\0'; - } - sensor_name[++i] = '.'; - sensor_name[++i] = '.'; - } - - canvas_draw_str_aligned( - canvas, pos[0] + 27, pos[1] + 3, AlignCenter, AlignCenter, sensor_name); - _draw_temperature(canvas, sensor, pos[0], pos[1] + 8, color); -} - -static void _draw_view_noSensors(Canvas* canvas) { - canvas_draw_icon(canvas, 7, 17, &I_sherlok_53x45); - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 63, 10, AlignCenter, AlignCenter, "No sensors found"); - canvas_set_font(canvas, FontSecondary); - const uint8_t x = 65, y = 32; - canvas_draw_rframe(canvas, x - 4, y - 11, 54, 33, 3); - canvas_draw_rframe(canvas, x - 4, y - 11, 54, 34, 3); - canvas_draw_str(canvas, x, y, "To add the"); - canvas_draw_str(canvas, x, y + 9, "new sensor"); - canvas_draw_str(canvas, x, y + 18, "press OK"); - - canvas_draw_icon(canvas, x + 37, y + 10, &I_Ok_btn_9x9); -} - -static void _draw_view_sensorsList(Canvas* canvas) { - //Текущая страница - uint8_t page = generalview_sensor_index / 4; - //Количество датчиков, которые будут отображаться на странице - uint8_t page_sensors_count; - if((unitemp_sensors_getActiveCount() - page * 4) / 4) { - page_sensors_count = 4; - } else { - page_sensors_count = (unitemp_sensors_getActiveCount() - page * 4) % 4; - } - - //Количество страниц - uint8_t pages = - unitemp_sensors_getActiveCount() / 4 + (unitemp_sensors_getActiveCount() % 4 ? 1 : 0); - - //Стрелка влево - if(page > 0) { - canvas_draw_icon(canvas, 2, 32, &I_ButtonLeft_4x7); - } - //Стрелка вправо - if(pages > 0 && page < pages - 1) { - canvas_draw_icon(canvas, 122, 32, &I_ButtonRight_4x7); - } - - const uint8_t value_positions[][4][2] = { - {{36, 18}}, //1 датчик - {{7, 18}, {67, 18}}, //2 датчика - {{7, 3}, {67, 3}, {37, 33}}, //3 датчика - {{7, 3}, {67, 3}, {7, 33}, {67, 33}}}; //4 датчика - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - for(uint8_t i = 0; i < page_sensors_count; i++) { - _draw_singleSensor( - canvas, - unitemp_sensor_getActive(page * 4 + i), - value_positions[page_sensors_count - 1][i], - ColorWhite); - } -} - -static void _draw_carousel_values(Canvas* canvas) { - UnitempStatus sensor_status = unitemp_sensor_getActive(generalview_sensor_index)->status; - if(sensor_status == UT_SENSORSTATUS_ERROR || sensor_status == UT_SENSORSTATUS_TIMEOUT) { - const Icon* frames[] = { - &I_flipper_happy_60x38, &I_flipper_happy_2_60x38, &I_flipper_sad_60x38}; - canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]); - - canvas_set_font(canvas, FontSecondary); - //TODO: Оптимизировать эту срань - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) { - snprintf( - app->buff, - BUFF_SIZE, - "Waiting for module on pin %d", - ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->gpio->num); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) { - snprintf( - app->buff, - BUFF_SIZE, - "Waiting for module on pin %d", - ((OneWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->bus->gpio->num); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { - snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins"); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { - snprintf(app->buff, BUFF_SIZE, "Waiting for module on SPI pins"); - } - canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff); - return; - } - - static const uint8_t temp_positions[3][2] = {{37, 23}, {37, 16}, {9, 16}}; - static const uint8_t hum_positions[2][2] = {{37, 38}, {65, 16}}; - //Селектор значений для отображения - switch(unitemp_sensor_getActive(generalview_sensor_index)->type->datatype) { - case UT_DATA_TYPE_TEMP: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[0][0], - temp_positions[0][1], - ColorWhite); - break; - case UT_DATA_TYPE_TEMP_HUM: - if(!app->settings.heat_index) { - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[1][0], - temp_positions[1][1], - ColorWhite); - } else { - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_heat_index( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - } - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[0]); - break; - case UT_DATA_TYPE_TEMP_PRESS: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[1][0], - temp_positions[1][1], - ColorWhite); - _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index)); - break; - case UT_DATA_TYPE_TEMP_HUM_PRESS: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index)); - break; - case UT_DATA_TYPE_TEMP_HUM_CO2: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - _draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite); - break; - } -} - -//TODO: Оптимизировать вывод информации -static void _draw_carousel_info(Canvas* canvas) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 23, "Type:"); - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) { - OneWireSensor* s = unitemp_sensor_getActive(generalview_sensor_index)->instance; - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "GPIO:"); - canvas_draw_str(canvas, 10, 47, "ID:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, - 41, - 23, - unitemp_onewire_sensor_getModel(unitemp_sensor_getActive(generalview_sensor_index))); - canvas_draw_str(canvas, 41, 35, s->bus->gpio->name); - snprintf( - app->buff, - BUFF_SIZE, - "%02X%02X%02X%02X%02X%02X%02X%02X", - s->deviceID[0], - s->deviceID[1], - s->deviceID[2], - s->deviceID[3], - s->deviceID[4], - s->deviceID[5], - s->deviceID[6], - s->deviceID[7]); - canvas_draw_str(canvas, 24, 47, app->buff); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "GPIO:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - canvas_draw_str( - canvas, - 41, - 35, - ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->gpio->name); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "MISO pin:"); - canvas_draw_str(canvas, 10, 46, "CS pin:"); - canvas_draw_str(canvas, 10, 58, "SCK pin:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - canvas_draw_str(canvas, 60, 35, unitemp_gpio_getFromInt(3)->name); - canvas_draw_str( - canvas, - 47, - 46, - ((SPISensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->CS_pin->name); - canvas_draw_str(canvas, 54, 58, unitemp_gpio_getFromInt(5)->name); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "I2C addr:"); - canvas_draw_str(canvas, 10, 46, "SDA pin:"); - canvas_draw_str(canvas, 10, 58, "SCL pin:"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - snprintf( - app->buff, - BUFF_SIZE, - "0x%02X", - ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->currentI2CAdr >> - 1); - canvas_draw_str(canvas, 57, 35, app->buff); - canvas_draw_str(canvas, 54, 46, "15 (C1)"); - canvas_draw_str(canvas, 54, 58, "16 (C0)"); - } -} -static void _draw_view_sensorsCarousel(Canvas* canvas) { - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - - //Печать имени - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 7, - AlignCenter, - AlignCenter, - unitemp_sensor_getActive(generalview_sensor_index)->name); - //Подчёркивание - uint8_t line_len = - canvas_string_width(canvas, unitemp_sensor_getActive(generalview_sensor_index)->name) + 2; - canvas_draw_line(canvas, 64 - line_len / 2, 12, 64 + line_len / 2, 12); - - //Стрелка вправо - if(unitemp_sensors_getTypesCount() > 0 && - generalview_sensor_index < unitemp_sensors_getActiveCount() - 1) { - canvas_draw_icon(canvas, 122, 29, &I_ButtonRight_4x7); - } - //Стрелка влево - if(generalview_sensor_index > 0) { - canvas_draw_icon(canvas, 2, 29, &I_ButtonLeft_4x7); - } - - switch(carousel_info_selector) { - case CAROUSEL_VALUES: - _draw_carousel_values(canvas); - break; - case CAROUSEL_INFO: - _draw_carousel_info(canvas); - break; - } -} - -static void _draw_callback(Canvas* canvas, void* _model) { - UNUSED(_model); - - app->sensors_ready = true; - - uint8_t sensors_count = unitemp_sensors_getActiveCount(); - - if(generalview_sensor_index + 1 > sensors_count) generalview_sensor_index = 0; - - if(sensors_count == 0) { - current_view = G_NO_SENSORS_VIEW; - _draw_view_noSensors(canvas); - } else { - if(sensors_count == 1) current_view = G_CAROUSEL_VIEW; - if(current_view == G_NO_SENSORS_VIEW) current_view = G_CAROUSEL_VIEW; - if(current_view == G_LIST_VIEW) _draw_view_sensorsList(canvas); - if(current_view == G_CAROUSEL_VIEW) _draw_view_sensorsCarousel(canvas); - } -} - -static bool _input_callback(InputEvent* event, void* context) { - UNUSED(context); - - //Обработка короткого нажатия "ок" - if(event->key == InputKeyOk && event->type == InputTypeShort) { - //Меню добавления датчика при их отсутствии - if(current_view == G_NO_SENSORS_VIEW) { - app->sensors_ready = false; - unitemp_SensorsList_switch(); - } else if(current_view == G_LIST_VIEW) { - //Переход в главное меню при выключенном селекторе - app->sensors_ready = false; - unitemp_MainMenu_switch(); - } else if(current_view == G_CAROUSEL_VIEW) { - app->sensors_ready = false; - unitemp_SensorActions_switch(unitemp_sensor_getActive(generalview_sensor_index)); - } - } - - //Обработка короткого нажатия "вниз" - if(event->key == InputKeyDown && event->type == InputTypeShort) { - //Переход из значений в информацию в карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES) { - carousel_info_selector = CAROUSEL_INFO; - return true; - } - //Переход в карусель из списка - if(current_view == G_LIST_VIEW) { - current_view = G_CAROUSEL_VIEW; - return true; - } - } - - //Обработка короткого нажатия "вверх" - if(event->key == InputKeyUp && event->type == InputTypeShort) { - //Переход из информации в значения в карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_INFO) { - carousel_info_selector = CAROUSEL_VALUES; - return true; - } - //Переход в список из карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES && - unitemp_sensors_getActiveCount() > 1) { - current_view = G_LIST_VIEW; - return true; - } - } - - //Обработка короткого нажатия "вправо" - if(event->key == InputKeyRight && event->type == InputTypeShort) { - //Пролистывание карусели вперёд - if(current_view == G_CAROUSEL_VIEW) { - if(++generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = 0; - if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW; - } - - return true; - } - //Пролистывание списка вперёд - if(current_view == G_LIST_VIEW) { - generalview_sensor_index += 4; - if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = 0; - current_view = G_CAROUSEL_VIEW; - } - return true; - } - } - - //Обработка короткого нажатия "влево" - if(event->key == InputKeyLeft && event->type == InputTypeShort) { - //Пролистывание карусели назад - if(current_view == G_CAROUSEL_VIEW) { - if(--generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW; - } - - return true; - } - //Пролистывание списка назад - if(current_view == G_LIST_VIEW) { - generalview_sensor_index -= 4; - if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - current_view = G_CAROUSEL_VIEW; - } - - return true; - } - } - - //Обработка короткого нажатия "назад" - if(event->key == InputKeyBack && event->type == InputTypeShort) { - //Выход из приложения при карусели или отсутствии датчиков - if(current_view == G_NO_SENSORS_VIEW || - ((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector == CAROUSEL_VALUES))) { - app->processing = false; - return true; - } - //Переключение селектора вида карусели - if((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector != CAROUSEL_VALUES)) { - carousel_info_selector = CAROUSEL_VALUES; - return true; - } - //Переход в карусель из списка - if(current_view == G_LIST_VIEW) { - current_view = G_CAROUSEL_VIEW; - return true; - } - } - //Обработка длинного нажатия "Ок" - if(event->key == InputKeyOk && event->type == InputTypeLong) { - app->settings.temp_unit = !app->settings.temp_unit; - } - - return true; -} - -void unitemp_General_alloc(void) { - view = view_alloc(); - view_set_context(view, app); - view_set_draw_callback(view, _draw_callback); - view_set_input_callback(view, _input_callback); - - view_dispatcher_add_view(app->view_dispatcher, UnitempViewGeneral, view); -} - -void unitemp_General_switch(void) { - app->sensors_ready = true; - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewGeneral); -} - -void unitemp_General_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewGeneral); - view_free(view); -} diff --git a/applications/external/unitemp/views/MainMenu_view.c b/applications/external/unitemp/views/MainMenu_view.c deleted file mode 100644 index bfd0cb0cf..000000000 --- a/applications/external/unitemp/views/MainMenu_view.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -#define VIEW_ID UnitempViewMainMenu - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - //Возврат в общий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - if(index == 0) { //Add new sensor - unitemp_SensorsList_switch(); - } - if(index == 1) { //Settings - unitemp_Settings_switch(); - } - if(index == 2) { - unitemp_widget_help_switch(); - } - if(index == 3) { - unitemp_widget_about_switch(); - } -} - -/** - * @brief Создание списка действий с указанным датчиком - */ -void unitemp_MainMenu_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "About", 1, NULL, NULL); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_MainMenu_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - //Переключение в вид - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_MainMenu_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/Popup_view.c b/applications/external/unitemp/views/Popup_view.c deleted file mode 100644 index efa7e7ffa..000000000 --- a/applications/external/unitemp/views/Popup_view.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -uint32_t _prev_view_id; - -#define VIEW_ID UnitempViewPopup - -static void _popup_callback(void* context) { - UNUSED(context); - view_dispatcher_switch_to_view(app->view_dispatcher, _prev_view_id); -} - -void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id) { - _prev_view_id = prev_view_id; - popup_reset(app->popup); - popup_set_icon(app->popup, 0, 64 - icon_get_height(icon), icon); - popup_set_header(app->popup, header, 64, 6, AlignCenter, AlignCenter); - popup_set_text( - app->popup, - message, - (128 - icon_get_width(icon)) / 2 + icon_get_width(icon), - 32, - AlignCenter, - AlignCenter); - - popup_set_timeout(app->popup, 5000); - popup_set_callback(app->popup, _popup_callback); - popup_enable_timeout(app->popup); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorActions_view.c b/applications/external/unitemp/views/SensorActions_view.c deleted file mode 100644 index 1d1a83076..000000000 --- a/applications/external/unitemp/views/SensorActions_view.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; -//Текущий датчик -static Sensor* current_sensor; - -typedef enum carousel_info { - CAROUSEL_VALUES, //Отображение значений датчиков - CAROUSEL_INFO, //Отображение информации о датчике -} carousel_info; -extern carousel_info carousel_info_selector; - -#define VIEW_ID UnitempViewSensorActions - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - switch(index) { - case 0: - carousel_info_selector = CAROUSEL_INFO; - unitemp_General_switch(); - return; - case 1: - unitemp_SensorEdit_switch(current_sensor); - break; - case 2: - unitemp_widget_delete_switch(current_sensor); - break; - case 3: - unitemp_SensorsList_switch(); - break; - case 4: - unitemp_Settings_switch(); - break; - case 5: - unitemp_widget_help_switch(); - break; - case 6: - unitemp_widget_about_switch(); - break; - } -} - -/** - * @brief Создание меню действий с датчиком - */ -void unitemp_SensorActions_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - variable_item_list_add(variable_item_list, "Info", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Edit", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Delete", 1, NULL, NULL); - - variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "About", 1, NULL, NULL); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_SensorActions_switch(Sensor* sensor) { - current_sensor = sensor; - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorActions_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorEdit_view.c b/applications/external/unitemp/views/SensorEdit_view.c deleted file mode 100644 index c1ac4c028..000000000 --- a/applications/external/unitemp/views/SensorEdit_view.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -#include "../interfaces/SingleWireSensor.h" -#include "../interfaces/OneWireSensor.h" -#include "../interfaces/I2CSensor.h" - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; -//Текущий редактируемый датчик -static Sensor* editable_sensor; -//Изначальный GPIO датчика -static const GPIO* initial_gpio = NULL; - -//Элемент списка - имя датчика -static VariableItem* sensor_name_item; -//Элемент списка - адрес датчика one wire -static VariableItem* onewire_addr_item; -//Элемент списка - адрес датчика one wire -static VariableItem* onewire_type_item; -//Элемент списка - смещение температуры -VariableItem* temp_offset_item; - -#define OFFSET_BUFF_SIZE 5 -//Буффер для текста смещения -static char* offset_buff; - -extern uint8_t generalview_sensor_index; - -#define VIEW_ID UnitempViewSensorEdit - -bool _onewire_id_exist(uint8_t* id) { - if(id == NULL) return false; - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type == &Dallas) { - if(unitemp_onewire_id_compare( - id, ((OneWireSensor*)(unitemp_sensor_getActive(i)->instance))->deviceID)) { - return true; - } - } - } - return false; -} - -static void _onewire_scan(void) { - OneWireSensor* ow_sensor = editable_sensor->instance; - - UNITEMP_DEBUG( - "devices on wire %d: %d", ow_sensor->bus->gpio->num, ow_sensor->bus->device_count); - - //Сканирование шины one wire - unitemp_onewire_bus_init(ow_sensor->bus); - uint8_t* id = NULL; - do { - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - } while(_onewire_id_exist(id)); - - if(id == NULL) { - unitemp_onewire_bus_enum_init(ow_sensor->bus); - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - if(_onewire_id_exist(id)) { - do { - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - } while(_onewire_id_exist(id) && id != NULL); - } - if(id == NULL) { - memset(ow_sensor->deviceID, 0, 8); - ow_sensor->familyCode = 0; - unitemp_onewire_bus_deinit(ow_sensor->bus); - variable_item_set_current_value_text(onewire_addr_item, "empty"); - variable_item_set_current_value_text( - onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor)); - return; - } - } - - unitemp_onewire_bus_deinit(ow_sensor->bus); - - memcpy(ow_sensor->deviceID, id, 8); - ow_sensor->familyCode = id[0]; - - UNITEMP_DEBUG( - "Found sensor's ID: %02X%02X%02X%02X%02X%02X%02X%02X", - id[0], - id[1], - id[2], - id[3], - id[4], - id[5], - id[6], - id[7]); - - if(ow_sensor->familyCode != 0) { - char id_buff[10]; - snprintf( - id_buff, - 10, - "%02X%02X%02X", - ow_sensor->deviceID[1], - ow_sensor->deviceID[2], - ow_sensor->deviceID[3]); - //А больше не лезет( - variable_item_set_current_value_text(onewire_addr_item, id_buff); - } else { - variable_item_set_current_value_text(onewire_addr_item, "empty"); - } - variable_item_set_current_value_text( - onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor)); -} - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - editable_sensor->status = UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensor_free(editable_sensor); - unitemp_sensors_reload(); - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - //Смена имени - if(index == 0) { - unitemp_SensorNameEdit_switch(editable_sensor); - } - //Сохранение - if((index == 4 && editable_sensor->type->interface != &ONE_WIRE) || - (index == 5 && editable_sensor->type->interface == &ONE_WIRE)) { - //Выход если датчик one wire не имеет ID - if(editable_sensor->type->interface == &ONE_WIRE && - ((OneWireSensor*)(editable_sensor->instance))->familyCode == 0) { - return; - } - if(initial_gpio != NULL) { - unitemp_gpio_unlock(initial_gpio); - initial_gpio = NULL; - } - editable_sensor->status = UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensors_add(editable_sensor); - unitemp_sensors_save(); - unitemp_sensors_reload(); - - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - unitemp_General_switch(); - } - - //Адрес устройства на шине one wire - if(index == 4 && editable_sensor->type->interface == &ONE_WIRE) { - _onewire_scan(); - } -} - -/** - * @brief Функция обработки изменения значения GPIO - * - * @param item Указатель на элемент списка - */ -static void _gpio_change_callback(VariableItem* item) { - uint8_t index = variable_item_get_current_value_index(item); - if(editable_sensor->type->interface == &SINGLE_WIRE) { - SingleWireSensor* instance = editable_sensor->instance; - instance->gpio = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); - variable_item_set_current_value_text(item, instance->gpio->name); - } - if(editable_sensor->type->interface == &SPI) { - SPISensor* instance = editable_sensor->instance; - instance->CS_pin = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); - variable_item_set_current_value_text(item, instance->CS_pin->name); - } - if(editable_sensor->type->interface == &ONE_WIRE) { - OneWireSensor* instance = editable_sensor->instance; - instance->bus->gpio = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, NULL); - variable_item_set_current_value_text(item, instance->bus->gpio->name); - } -} -/** - * @brief Функция обработки изменения значения GPIO - * - * @param item Указатель на элемент списка - */ -static void _i2caddr_change_callback(VariableItem* item) { - uint8_t index = variable_item_get_current_value_index(item); - ((I2CSensor*)editable_sensor->instance)->currentI2CAdr = - ((I2CSensor*)editable_sensor->instance)->minI2CAdr + index * 2; - char buff[5]; - snprintf(buff, 5, "0x%2X", ((I2CSensor*)editable_sensor->instance)->currentI2CAdr >> 1); - variable_item_set_current_value_text(item, buff); -} -/** - * @brief Функция обработки изменения значения имени датчика - * - * @param item Указатель на элемент списка - */ -static void _name_change_callback(VariableItem* item) { - variable_item_set_current_value_index(item, 0); - unitemp_SensorNameEdit_switch(editable_sensor); -} -/** - * @brief Функция обработки изменения значения адреса датчика one wire - * - * @param item Указатель на элемент списка - */ -static void _onwire_addr_change_callback(VariableItem* item) { - variable_item_set_current_value_index(item, 0); - _onewire_scan(); -} - -/** - * @brief Функция обработки изменения значения смещения температуры - * - * @param item Указатель на элемент списка - */ -static void _offset_change_callback(VariableItem* item) { - editable_sensor->temp_offset = variable_item_get_current_value_index(item) - 20; - snprintf( - offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0)); - variable_item_set_current_value_text(item, offset_buff); -} - -/** - * @brief Создание меню редактирования датчка - */ -void unitemp_SensorEdit_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); - - offset_buff = malloc(OFFSET_BUFF_SIZE); -} - -void unitemp_SensorEdit_switch(Sensor* sensor) { - editable_sensor = sensor; - - editable_sensor->status = UT_SENSORSTATUS_INACTIVE; - - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - //Имя датчика - sensor_name_item = variable_item_list_add( - variable_item_list, "Name", strlen(sensor->name) > 7 ? 1 : 2, _name_change_callback, NULL); - variable_item_set_current_value_index(sensor_name_item, 0); - variable_item_set_current_value_text(sensor_name_item, sensor->name); - - //Тип датчика (не редактируется) - onewire_type_item = variable_item_list_add(variable_item_list, "Type", 1, NULL, NULL); - variable_item_set_current_value_index(onewire_type_item, 0); - variable_item_set_current_value_text( - onewire_type_item, - (sensor->type->interface == &ONE_WIRE ? unitemp_onewire_sensor_getModel(editable_sensor) : - sensor->type->typename)); - //Смещение температуры - temp_offset_item = variable_item_list_add( - variable_item_list, "Temp. offset", 41, _offset_change_callback, NULL); - variable_item_set_current_value_index(temp_offset_item, sensor->temp_offset + 20); - snprintf( - offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0)); - variable_item_set_current_value_text(temp_offset_item, offset_buff); - - //Порт подключения датчка (для one wire, SPI и single wire) - if(sensor->type->interface == &ONE_WIRE || sensor->type->interface == &SINGLE_WIRE || - sensor->type->interface == &SPI) { - if(sensor->type->interface == &ONE_WIRE) { - initial_gpio = ((OneWireSensor*)editable_sensor->instance)->bus->gpio; - } else if(sensor->type->interface == &SINGLE_WIRE) { - initial_gpio = ((SingleWireSensor*)editable_sensor->instance)->gpio; - } else if(sensor->type->interface == &SPI) { - initial_gpio = ((SPISensor*)editable_sensor->instance)->CS_pin; - } - - uint8_t aviable_gpio_count = - unitemp_gpio_getAviablePortsCount(sensor->type->interface, initial_gpio); - VariableItem* item = variable_item_list_add( - variable_item_list, "GPIO", aviable_gpio_count, _gpio_change_callback, app); - - uint8_t gpio_index = 0; - if(unitemp_sensor_isContains(editable_sensor)) { - for(uint8_t i = 0; i < aviable_gpio_count; i++) { - if(unitemp_gpio_getAviablePort(sensor->type->interface, i, initial_gpio) == - initial_gpio) { - gpio_index = i; - break; - } - } - } - variable_item_set_current_value_index(item, gpio_index); - variable_item_set_current_value_text( - item, - unitemp_gpio_getAviablePort(sensor->type->interface, gpio_index, initial_gpio)->name); - } - //Адрес устройства на шине I2C (для датчиков I2C) - if(sensor->type->interface == &I2C) { - VariableItem* item = variable_item_list_add( - variable_item_list, - "I2C address", - (((I2CSensor*)sensor->instance)->maxI2CAdr >> 1) - - (((I2CSensor*)sensor->instance)->minI2CAdr >> 1) + 1, - _i2caddr_change_callback, - app); - snprintf(app->buff, 5, "0x%2X", ((I2CSensor*)sensor->instance)->currentI2CAdr >> 1); - variable_item_set_current_value_index( - item, - (((I2CSensor*)sensor->instance)->currentI2CAdr >> 1) - - (((I2CSensor*)sensor->instance)->minI2CAdr >> 1)); - variable_item_set_current_value_text(item, app->buff); - } - - //Адрес устройства на шине one wire (для датчиков one wire) - if(sensor->type->interface == &ONE_WIRE) { - onewire_addr_item = variable_item_list_add( - variable_item_list, "Address", 2, _onwire_addr_change_callback, NULL); - OneWireSensor* ow_sensor = sensor->instance; - if(ow_sensor->familyCode == 0) { - variable_item_set_current_value_text(onewire_addr_item, "Scan"); - } else { - snprintf( - app->buff, - 10, - "%02X%02X%02X", - ow_sensor->deviceID[1], - ow_sensor->deviceID[2], - ow_sensor->deviceID[3]); - variable_item_set_current_value_text(onewire_addr_item, app->buff); - } - } - variable_item_list_add(variable_item_list, "Save", 1, NULL, NULL); - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorEdit_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); - free(offset_buff); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorNameEdit_view.c b/applications/external/unitemp/views/SensorNameEdit_view.c deleted file mode 100644 index 19df76edf..000000000 --- a/applications/external/unitemp/views/SensorNameEdit_view.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Окно ввода текста -static TextInput* text_input; -//Текущий редактируемый датчик -static Sensor* editable_sensor; - -#define VIEW_ID UnitempViewSensorNameEdit - -static void _sensor_name_changed_callback(void* context) { - UNUSED(context); - unitemp_SensorEdit_switch(editable_sensor); -} - -void unitemp_SensorNameEdit_alloc(void) { - text_input = text_input_alloc(); - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, text_input_get_view(text_input)); - text_input_set_header_text(text_input, "Sensor name"); -} -void unitemp_SensorNameEdit_switch(Sensor* sensor) { - editable_sensor = sensor; - text_input_set_result_callback( - text_input, _sensor_name_changed_callback, app, sensor->name, 11, true); - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} -void unitemp_SensorNameEdit_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); - text_input_free(text_input); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorsList_view.c b/applications/external/unitemp/views/SensorsList_view.c deleted file mode 100644 index 716ec260b..000000000 --- a/applications/external/unitemp/views/SensorsList_view.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -extern const Icon I_Cry_dolph_55x52; - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -#define VIEW_ID UnitempViewSensorsList - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - if(index == unitemp_sensors_getTypesCount()) { - unitemp_widget_help_switch(); - return; - } - - const SensorType* type = unitemp_sensors_getTypes()[index]; - uint8_t sensor_type_count = 0; - - //Подсчёт имеющихся датчиков данного типа - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type == type) { - sensor_type_count++; - } - } - - //Имя датчка - char sensor_name[11]; - //Добавление счётчика к имени если такой датчик имеется - if(sensor_type_count == 0) - snprintf(sensor_name, 11, "%s", type->typename); - else - snprintf(sensor_name, 11, "%s_%d", type->typename, sensor_type_count); - - char args[22] = {0}; - - //Проверка доступности датчика - if(unitemp_gpio_getAviablePort(type->interface, 0, NULL) == NULL) { - if(type->interface == &SINGLE_WIRE || type->interface == &ONE_WIRE) { - unitemp_popup( - &I_Cry_dolph_55x52, "Sensor is unavailable", "All GPIOs\nare busy", VIEW_ID); - } - if(type->interface == &I2C) { - unitemp_popup( - &I_Cry_dolph_55x52, "Sensor is unavailable", "GPIOs 15 or 16\nare busy", VIEW_ID); - } - return; - } - - //Выбор первого доступного порта для датчика single wire и SPI - if(type->interface == &SINGLE_WIRE || type->interface == &SPI) { - snprintf( - args, - 4, - "%d", - unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL))); - } - //Выбор первого доступного порта для датчика one wire и запись нулевого ID - if(type->interface == &ONE_WIRE) { - snprintf( - args, - 21, - "%d %02X%02X%02X%02X%02X%02X%02X%02X", - unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL)), - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0); - } - //Для I2C адрес выберется автоматически - - unitemp_SensorEdit_switch(unitemp_sensor_alloc(sensor_name, type, args)); -} - -/** - * @brief Создание меню редактирования настроек - */ -void unitemp_SensorsList_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - //Добавление в список доступных датчиков - for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) { - if(unitemp_sensors_getTypes()[i]->altname == NULL) { - variable_item_list_add( - variable_item_list, unitemp_sensors_getTypes()[i]->typename, 1, NULL, app); - } else { - variable_item_list_add( - variable_item_list, unitemp_sensors_getTypes()[i]->altname, 1, NULL, app); - } - } - variable_item_list_add(variable_item_list, "I don't know what to choose", 1, NULL, app); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_SensorsList_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorsList_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/Settings_view.c b/applications/external/unitemp/views/Settings_view.c deleted file mode 100644 index 3d1eca906..000000000 --- a/applications/external/unitemp/views/Settings_view.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -static const char states[2][9] = {"Auto", "Infinity"}; -static const char temp_units[UT_TEMP_COUNT][3] = {"*C", "*F"}; -static const char pressure_units[UT_PRESSURE_COUNT][6] = {"mm Hg", "in Hg", "kPa", "hPA"}; -static const char heat_index_bool[2][4] = {"OFF", "ON"}; - -//Элемент списка - бесконечная подсветка -VariableItem* infinity_backlight_item; -//Единица измерения температуры -VariableItem* temperature_unit_item; -//Единица измерения давления -VariableItem* pressure_unit_item; - -VariableItem* heat_index_item; -#define VIEW_ID UnitempViewSettings - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - //Костыль с зависающей подсветкой - if((bool)variable_item_get_current_value_index(infinity_backlight_item) != - app->settings.infinityBacklight) { - if((bool)variable_item_get_current_value_index(infinity_backlight_item)) { - notification_message(app->notifications, &sequence_display_backlight_enforce_on); - } else { - notification_message(app->notifications, &sequence_display_backlight_enforce_auto); - } - } - - app->settings.infinityBacklight = - (bool)variable_item_get_current_value_index(infinity_backlight_item); - app->settings.temp_unit = variable_item_get_current_value_index(temperature_unit_item); - app->settings.pressure_unit = variable_item_get_current_value_index(pressure_unit_item); - app->settings.heat_index = variable_item_get_current_value_index(heat_index_item); - unitemp_saveSettings(); - unitemp_loadSettings(); - - //Возврат предыдущий вид - return UnitempViewMainMenu; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - UNUSED(index); -} - -static void _setting_change_callback(VariableItem* item) { - if(item == infinity_backlight_item) { - variable_item_set_current_value_text( - infinity_backlight_item, - states[variable_item_get_current_value_index(infinity_backlight_item)]); - } - if(item == temperature_unit_item) { - variable_item_set_current_value_text( - temperature_unit_item, - temp_units[variable_item_get_current_value_index(temperature_unit_item)]); - } - if(item == pressure_unit_item) { - variable_item_set_current_value_text( - pressure_unit_item, - pressure_units[variable_item_get_current_value_index(pressure_unit_item)]); - } - if(item == heat_index_item) { - variable_item_set_current_value_text( - heat_index_item, - heat_index_bool[variable_item_get_current_value_index(heat_index_item)]); - } -} - -/** - * @brief Создание меню редактирования настроек - */ -void unitemp_Settings_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - infinity_backlight_item = variable_item_list_add( - variable_item_list, "Backlight time", UT_TEMP_COUNT, _setting_change_callback, app); - temperature_unit_item = - variable_item_list_add(variable_item_list, "Temp. unit", 2, _setting_change_callback, app); - pressure_unit_item = variable_item_list_add( - variable_item_list, "Press. unit", UT_PRESSURE_COUNT, _setting_change_callback, app); - heat_index_item = variable_item_list_add( - variable_item_list, "Calc. heat index", 2, _setting_change_callback, app); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_Settings_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - variable_item_set_current_value_index( - infinity_backlight_item, (uint8_t)app->settings.infinityBacklight); - variable_item_set_current_value_text( - infinity_backlight_item, - states[variable_item_get_current_value_index(infinity_backlight_item)]); - - variable_item_set_current_value_index(temperature_unit_item, (uint8_t)app->settings.temp_unit); - variable_item_set_current_value_text( - temperature_unit_item, - temp_units[variable_item_get_current_value_index(temperature_unit_item)]); - - variable_item_set_current_value_index( - pressure_unit_item, (uint8_t)app->settings.pressure_unit); - variable_item_set_current_value_text( - pressure_unit_item, - pressure_units[variable_item_get_current_value_index(pressure_unit_item)]); - - variable_item_set_current_value_index(heat_index_item, (uint8_t)app->settings.heat_index); - variable_item_set_current_value_text( - heat_index_item, heat_index_bool[variable_item_get_current_value_index(heat_index_item)]); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_Settings_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} diff --git a/applications/external/unitemp/views/UnitempViews.h b/applications/external/unitemp/views/UnitempViews.h deleted file mode 100644 index b78cf2b28..000000000 --- a/applications/external/unitemp/views/UnitempViews.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCENES -#define UNITEMP_SCENES - -#include "../unitemp.h" - -//Виды менюшек -typedef enum UnitempViews { - UnitempViewGeneral, - UnitempViewMainMenu, - UnitempViewSettings, - UnitempViewSensorsList, - UnitempViewSensorEdit, - UnitempViewSensorNameEdit, - UnitempViewSensorActions, - UnitempViewWidget, - UnitempViewPopup, - - UnitempViewsCount -} UnitempViews; - -/** - * @brief Вывести всплывающее окно - * - * @param icon Указатель на иконку - * @param header Заголовок - * @param message Сообщение - * @param prev_view_id ID вида куда в который нужно вернуться - */ -void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id); - -/* Общий вид на датчики */ -void unitemp_General_alloc(void); -void unitemp_General_switch(void); -void unitemp_General_free(void); - -/* Главное меню */ -void unitemp_MainMenu_alloc(void); -void unitemp_MainMenu_switch(void); -void unitemp_MainMenu_free(void); - -/* Настройки */ -void unitemp_Settings_alloc(void); -void unitemp_Settings_switch(void); -void unitemp_Settings_free(void); - -/* Список датчиков */ -void unitemp_SensorsList_alloc(void); -void unitemp_SensorsList_switch(void); -void unitemp_SensorsList_free(void); - -/* Редактор датчка */ -void unitemp_SensorEdit_alloc(void); -//sensor - указатель на редактируемый датчик -void unitemp_SensorEdit_switch(Sensor* sensor); -void unitemp_SensorEdit_free(void); - -/* Редактор имени датчика */ -void unitemp_SensorNameEdit_alloc(void); -void unitemp_SensorNameEdit_switch(Sensor* sensor); -void unitemp_SensorNameEdit_free(void); - -/* Список действий с датчиком */ -void unitemp_SensorActions_alloc(void); -void unitemp_SensorActions_switch(Sensor* sensor); -void unitemp_SensorActions_free(void); - -/* Виджеты */ -void unitemp_widgets_alloc(void); -void unitemp_widgets_free(void); - -/* Подтверждение удаления */ -void unitemp_widget_delete_switch(Sensor* sensor); -/* Помощь */ -void unitemp_widget_help_switch(void); -/* О приложении */ -void unitemp_widget_about_switch(void); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/views/Widgets_view.c b/applications/external/unitemp/views/Widgets_view.c deleted file mode 100644 index 3055930cf..000000000 --- a/applications/external/unitemp/views/Widgets_view.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include "unitemp_icons.h" -#include - -// extern const Icon I_DolphinCommon_56x48; - -void unitemp_widgets_alloc(void) { - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, UnitempViewWidget, widget_get_view(app->widget)); -} - -void unitemp_widgets_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewWidget); - widget_free(app->widget); -} - -/* ================== Подтверждение удаления ================== */ -Sensor* current_sensor; -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _delete_exit_callback(void* context) { - UNUSED(context); - //Возвращаем ID вида, в который нужно вернуться - return UnitempViewSensorActions; -} -/** - * @brief Обработчик нажатий на кнопку в виджете - * - * @param result Какая из кнопок была нажата - * @param type Тип нажатия - * @param context Указатель на данные плагина - */ -static void _delete_click_callback(GuiButtonType result, InputType type, void* context) { - UNUSED(context); - //Коротко нажата левая кнопка (Cancel) - if(result == GuiButtonTypeLeft && type == InputTypeShort) { - unitemp_SensorActions_switch(current_sensor); - } - //Коротко нажата правая кнопка (Delete) - if(result == GuiButtonTypeRight && type == InputTypeShort) { - //Удаление датчика - unitemp_sensor_delete(current_sensor); - //Выход из меню - unitemp_General_switch(); - } -} -/** - * @brief Переключение в виджет удаления датчика - */ -void unitemp_widget_delete_switch(Sensor* sensor) { - current_sensor = sensor; - //Очистка виджета - widget_reset(app->widget); - //Добавление кнопок - widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Cancel", _delete_click_callback, app); - widget_add_button_element( - app->widget, GuiButtonTypeRight, "Delete", _delete_click_callback, app); - - snprintf(app->buff, BUFF_SIZE, "\e#Delete %s?\e#", current_sensor->name); - widget_add_text_box_element( - app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, app->buff, false); - - if(current_sensor->type->interface == &ONE_WIRE) { - OneWireSensor* s = current_sensor->instance; - - snprintf( - app->buff, - BUFF_SIZE, - "\e#Type:\e# %s", - unitemp_onewire_sensor_getModel(current_sensor)); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf(app->buff, BUFF_SIZE, "\e#GPIO:\e# %s", s->bus->gpio->name); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - - snprintf( - app->buff, - BUFF_SIZE, - "\e#ID:\e# %02X%02X%02X%02X%02X%02X%02X%02X", - s->deviceID[0], - s->deviceID[1], - s->deviceID[2], - s->deviceID[3], - s->deviceID[4], - s->deviceID[5], - s->deviceID[6], - s->deviceID[7]); - widget_add_text_box_element( - app->widget, 0, 40, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - if(current_sensor->type->interface == &SINGLE_WIRE) { - snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf( - app->buff, - BUFF_SIZE, - "\e#GPIO:\e# %s", - ((SingleWireSensor*)current_sensor->instance)->gpio->name); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - if(current_sensor->type->interface == &I2C) { - snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf( - app->buff, - BUFF_SIZE, - "\e#I2C addr:\e# 0x%02X", - ((I2CSensor*)current_sensor->instance)->currentI2CAdr >> 1); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - view_set_previous_callback(widget_get_view(app->widget), _delete_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} - -/* ========================== Помощь ========================== */ - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _help_exit_callback(void* context) { - UNUSED(context); - //Возвращаем ID вида, в который нужно вернуться - return UnitempViewGeneral; -} - -/** - * @brief Переключение в виджет помощи - */ -void unitemp_widget_help_switch(void) { - //Очистка виджета - widget_reset(app->widget); - - widget_add_icon_element(app->widget, 3, 7, &I_repo_qr_50x50); - widget_add_icon_element(app->widget, 71, 15, &I_DolphinCommon_56x48); - - widget_add_string_multiline_element( - app->widget, 55, 5, AlignLeft, AlignTop, FontSecondary, "You can find help\nthere"); - - widget_add_frame_element(app->widget, 0, 0, 128, 63, 7); - widget_add_frame_element(app->widget, 0, 0, 128, 64, 7); - - view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} - -/* ========================== О приложении ========================== */ - -/** - * @brief Переключение в виджет о приложении - */ -void unitemp_widget_about_switch(void) { - //Очистка виджета - widget_reset(app->widget); - - widget_add_frame_element(app->widget, 0, 0, 128, 63, 7); - widget_add_frame_element(app->widget, 0, 0, 128, 64, 7); - - snprintf(app->buff, BUFF_SIZE, "#Unitemp %s#", UNITEMP_APP_VER); - widget_add_text_box_element( - app->widget, 0, 4, 128, 12, AlignCenter, AlignCenter, app->buff, false); - - widget_add_text_scroll_element( - app->widget, - 4, - 16, - 121, - 44, - "Universal plugin for viewing the values of temperature\nsensors\n\e#Author: Quenon\ngithub.com/quen0n\n\e#Designer: Svaarich\ngithub.com/Svaarich\n\e#Issues & suggestions\ntiny.one/unitemp"); - - view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} diff --git a/applications/external/videopoker/application.fam b/applications/external/videopoker/application.fam deleted file mode 100644 index 4997132f2..000000000 --- a/applications/external/videopoker/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="videopoker", - name="Video Poker", - apptype=FlipperAppType.EXTERNAL, - entry_point="video_poker_app", - cdefines=["APP_VIDEOPOKER_GAME"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="pokerIcon.png", - fap_category="Games", - fap_author="@PixlEmly", - fap_weburl="https://github.com/PixlEmly", - fap_version="1.0", - fap_description="Video poker is a casino game based on five-card draw poker", -) diff --git a/applications/external/videopoker/poker.c b/applications/external/videopoker/poker.c deleted file mode 100644 index 20881529c..000000000 --- a/applications/external/videopoker/poker.c +++ /dev/null @@ -1,819 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/* Core game logic from -https://github.com/Yaoir/VideoPoker-C -*/ - -/* KNOWN BUGS -This has been converted from a standalone PC console app to flipper -All of the original input/output handing code has been ripped out -Original code also used TONS of defines and everything was a global. -As is, it does what I wanted and doesn't seem to have major issues, so that's pretty good. -Game logic is handled during input and this is a bit of a mess of nested ifs. -Sometimes duplicate cards will show up. there is a function to test this. I should use it better. - -*/ - -#define TAG "Video Poker" - -static void Shake(void) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_single_vibro); - furi_record_close(RECORD_NOTIFICATION); -} - -typedef struct { - int index; /* cards value, minus 1 */ - char* sym; /* text appearance */ - int suit; /* card's suit (see just below) */ - int gone; /* true if it's been dealt */ - int held; /* for hand */ -} PokerPlayer_card; - -typedef struct { - FuriMutex** model_mutex; - FuriMessageQueue* event_queue; - ViewPort* view_port; - Gui* gui; - PokerPlayer_card hand[5]; - PokerPlayer_card shand[5]; - PokerPlayer_card deck[52]; - int GameType; /* What rules are we using */ - int held[5]; - int score; - int highscore; - int pot; - int GameState; - int selected; - int bet; - int minbet; -} PokerPlayer; - -/* GameState -0=Splash/help, OK button (later on up/down for rules or settings) -1=cards down, betting enabled, left/right to change bet, OK to confirm -2=first hand, holding enabled, left/right to pick card, OK to hold/unhold card, down to confirm -3=second hand, only confirm to claim rewards -4=game over/won -5=WIP saving gamestate -*/ - -/* -#define AllAmerican 0 -#define TensOrBetter 1 -#define BonusPoker 2 -#define DoubleBonus 3 -#define DoubleBonusBonus 4 -#define JacksOrBetter 5 -#define JacksOrBetter95 6 -#define JacksOrBetter86 7 -#define JacksOrBetter85 8 -#define JacksOrBetter75 9 -#define JacksOrBetter65 10 -#define NUMGAMES 11 -*/ -/* - The game in play. Default is Jacks or Better, - which is coded into initialization of static data -*/ -const char* gamenames[11] = { - "All American", - "Tens or Better", - "Bonus Poker", - "Double Bonus", - "Double Bonus Bonus", - "Jacks or Better", - "9/5 Jacks or Better", - "8/6 Jacks or Better", - "8/5 Jacks or Better", - "7/5 Jacks or Better", - "6/5 Jacks or Better"}; - -PokerPlayer_card deck[52] = { - /* index, card name, suit, gone */ - /* Clubs:0 Diamonds:1 Hearts: 2 Spades: 3 */ - {1, "2", 0, 0, 0}, {2, "3", 0, 0, 0}, {3, "4", 0, 0, 0}, {4, "5", 0, 0, 0}, - {5, "6", 0, 0, 0}, {6, "7", 0, 0, 0}, {7, "8", 0, 0, 0}, {8, "9", 0, 0, 0}, - {9, "10", 0, 0, 0}, {10, "J", 0, 0, 0}, {11, "Q", 0, 0, 0}, {12, "K", 0, 0, 0}, - {13, "A", 0, 0, 0}, - - {1, "2", 1, 0, 0}, {2, "3", 1, 0, 0}, {3, "4", 1, 0, 0}, {4, "5", 1, 0, 0}, - {5, "6", 1, 0, 0}, {6, "7", 1, 0, 0}, {7, "8", 1, 0, 0}, {8, "9", 1, 0, 0}, - {9, "10", 1, 0, 0}, {10, "J", 1, 0, 0}, {11, "Q", 1, 0, 0}, {12, "K", 1, 0, 0}, - {13, "A", 1, 0, 0}, - - {1, "2", 2, 0, 0}, {2, "3", 2, 0, 0}, {3, "4", 2, 0, 0}, {4, "5", 2, 0, 0}, - {5, "6", 2, 0, 0}, {6, "7", 2, 0, 0}, {7, "8", 2, 0, 0}, {8, "9", 2, 0, 0}, - {9, "10", 2, 0, 0}, {10, "J", 2, 0, 0}, {11, "Q", 2, 0, 0}, {12, "K", 2, 0, 0}, - {13, "A", 2, 0, 0}, - - {1, "2", 3, 0, 0}, {2, "3", 3, 0, 0}, {3, "4", 3, 0, 0}, {4, "5", 3, 0, 0}, - {5, "6", 3, 0, 0}, {6, "7", 3, 0, 0}, {7, "8", 3, 0, 0}, {8, "9", 3, 0, 0}, - {9, "10", 3, 0, 0}, {10, "J", 3, 0, 0}, {11, "Q", 3, 0, 0}, {12, "K", 3, 0, 0}, - {13, "A", 3, 0, 0}, -}; - -/* -Image Format -0x01 = Compressed -0x00 = Reserved Section -0xa4,0x01 = 0x1a4, or, 420 - the size of the compressed array, minus this header. -Rest of the data is char array output from heatshrink of the original XBM char array. -Calculated Header: 0x01,0x00,0xa4,0x01 -from furi_hal_compress.c: -typedef struct { - uint8_t is_compressed; - uint8_t reserved; - uint16_t compressed_buff_size; -} FuriHalCompressHeader; -*/ - -const uint8_t _I_Splash_128x64_0[] = { - 0x01, 0x00, 0x8a, 0x02, 0x00, 0x78, 0x02, 0x60, 0xe0, 0x54, 0xc0, 0x03, 0x9f, 0xc0, 0x0f, 0x5a, - 0x04, 0x04, 0x1e, 0xdf, 0x08, 0x78, 0x0c, 0x60, 0xc0, 0x21, 0x90, 0x40, 0xa3, 0x00, 0xf5, 0xfe, - 0x61, 0xc1, 0xe9, 0x1e, 0x8e, 0x59, 0xf0, 0x02, 0x24, 0x9f, 0x70, 0xc0, 0x63, 0x03, 0x01, 0x0c, - 0x0b, 0xc1, 0x80, 0xbc, 0x83, 0xd3, 0x3f, 0x63, 0x98, 0x03, 0xcf, 0x88, 0x02, 0x1c, 0x31, 0x5d, - 0x38, 0xf6, 0x19, 0xc0, 0xa0, 0xfc, 0x93, 0x13, 0x12, 0xf0, 0x38, 0x76, 0x08, 0xc7, 0x00, 0x1e, - 0x5e, 0x8b, 0xcc, 0x32, 0x86, 0x0f, 0x4f, 0x0c, 0x80, 0x06, 0x20, 0x72, 0xe4, 0x5e, 0x33, 0xd4, - 0x73, 0xf2, 0x5d, 0xe2, 0x10, 0xef, 0xe6, 0x02, 0x0f, 0x07, 0x84, 0x4c, 0x33, 0xd2, 0x70, 0x79, - 0xd8, 0x2e, 0x11, 0x88, 0x3d, 0xff, 0xc1, 0xc7, 0x83, 0xc4, 0x20, 0x10, 0xc9, 0x18, 0x3d, 0x27, - 0x18, 0x8c, 0x3c, 0xde, 0xe1, 0xe6, 0x87, 0x7e, 0x0c, 0x62, 0x12, 0x10, 0x01, 0xce, 0x31, 0x9c, - 0x39, 0x9c, 0x62, 0x67, 0x0f, 0x83, 0x7f, 0x27, 0xe0, 0xf5, 0x8c, 0x71, 0xbc, 0x31, 0x8c, 0xc4, - 0xe2, 0x1e, 0x62, 0x1e, 0x02, 0xe0, 0x80, 0x05, 0x1c, 0xe1, 0xdc, 0x23, 0x97, 0xc8, 0xe4, 0x5c, - 0x12, 0x50, 0x40, 0x7a, 0x43, 0x38, 0x77, 0x88, 0xf4, 0x36, 0x3d, 0x1f, 0x04, 0x94, 0x20, 0x1e, - 0x98, 0xce, 0x0d, 0xbe, 0x37, 0x0d, 0xcd, 0xbd, 0x0c, 0x7e, 0xbe, 0xce, 0x07, 0x1f, 0xf3, 0xfc, - 0xf8, 0xb2, 0x8d, 0x30, 0x20, 0x53, 0xbe, 0x60, 0x06, 0x03, 0x78, 0xf0, 0x06, 0x4c, 0x1e, 0x34, - 0x10, 0x29, 0x5e, 0x05, 0x0f, 0x00, 0xa0, 0x40, 0x24, 0x20, 0x52, 0x76, 0x88, 0x01, 0xc1, 0xe3, - 0x11, 0x05, 0xc3, 0xe9, 0x20, 0x10, 0x97, 0x01, 0xcf, 0xc1, 0xf2, 0x81, 0x3f, 0xe7, 0xfc, 0x66, - 0xf4, 0x02, 0xf1, 0xc0, 0x3f, 0xdf, 0xf0, 0x30, 0xc6, 0x1e, 0xe5, 0xff, 0x81, 0xf0, 0x3f, 0xe5, - 0xb2, 0x80, 0x7f, 0xc1, 0xe5, 0x1c, 0x03, 0x0f, 0xe3, 0xff, 0x1f, 0xf8, 0x02, 0x48, 0x00, 0x31, - 0xfe, 0x0b, 0xa4, 0x61, 0xcc, 0x62, 0xfc, 0x4f, 0xe3, 0x0f, 0x31, 0x41, 0x0e, 0x02, 0x07, 0x01, - 0x07, 0x8a, 0xb4, 0xa3, 0x84, 0x71, 0x8f, 0xff, 0x20, 0x77, 0x00, 0x78, 0x95, 0x46, 0x06, 0x13, - 0x10, 0x78, 0xef, 0x3f, 0x5f, 0xfc, 0xff, 0xea, 0x07, 0xf0, 0x37, 0x90, 0x3c, 0x78, 0x00, 0xf2, - 0xae, 0x7f, 0x77, 0xf7, 0xaf, 0xec, 0x0f, 0x88, 0x41, 0x1b, 0x06, 0x02, 0x03, 0xc0, 0x02, 0x8c, - 0x08, 0x5c, 0x37, 0xff, 0xa9, 0x3c, 0x7b, 0xcc, 0x52, 0xe0, 0x70, 0x7c, 0x31, 0x89, 0xe4, 0xff, - 0xfb, 0xff, 0xdf, 0x8c, 0x46, 0x03, 0x1f, 0x34, 0x17, 0x83, 0xe1, 0x71, 0x8f, 0x6f, 0xe7, 0xe0, - 0xc1, 0x8f, 0xfd, 0x20, 0x18, 0x65, 0x59, 0x47, 0xaf, 0x9b, 0x8b, 0x9e, 0x6f, 0xe7, 0x1f, 0x16, - 0x0c, 0x3e, 0x3d, 0x00, 0xe4, 0x43, 0xd1, 0xe5, 0x3f, 0xe6, 0x6e, 0xfb, 0x39, 0x88, 0x67, 0xea, - 0xff, 0xc5, 0x22, 0x8f, 0xc0, 0xf0, 0x41, 0x71, 0xe7, 0x76, 0xf9, 0x98, 0x48, 0x64, 0x17, 0x59, - 0x38, 0x05, 0x8f, 0xc0, 0xd0, 0x5f, 0xe8, 0x0f, 0x1a, 0xdb, 0xe6, 0xb1, 0xd1, 0xa0, 0x50, 0x85, - 0x59, 0x7e, 0x16, 0x05, 0x06, 0x80, 0x71, 0xbf, 0xf7, 0x19, 0x85, 0x99, 0x74, 0x6d, 0x31, 0x02, - 0x10, 0x88, 0x7c, 0xdd, 0xdb, 0x84, 0x62, 0x7c, 0x0f, 0x38, 0xe5, 0xf0, 0x1e, 0x97, 0xce, 0x67, - 0xbc, 0xb6, 0x40, 0xa3, 0x98, 0x00, 0xc5, 0x76, 0x53, 0x8c, 0x67, 0x1e, 0x07, 0x0e, 0x63, 0x0a, - 0xe4, 0x9c, 0x62, 0x0f, 0x11, 0x41, 0x95, 0x88, 0x1e, 0x41, 0xd1, 0x8c, 0x49, 0x80, 0xe6, 0x00, - 0x50, 0xb8, 0xa3, 0x07, 0xf1, 0x7f, 0x06, 0xb8, 0x00, 0x61, 0xce, 0xb2, 0x9c, 0x53, 0x01, 0xf3, - 0xf0, 0x55, 0x97, 0xd0, 0x3f, 0x40, 0x03, 0xfd, 0x33, 0xc8, 0x01, 0x71, 0x92, 0x78, 0x80, 0x2f, - 0x80, 0x6f, 0x20, 0x03, 0xff, 0x23, 0xe7, 0x02, 0x02, 0x18, 0x01, 0xa3, 0x91, 0x00, 0x18, 0xc3, - 0x20, 0x91, 0xc0, 0x7c, 0x7f, 0x83, 0x42, 0xaa, 0x1f, 0xe0, 0xbe, 0x60, 0x46, 0xa2, 0x81, 0xe2, - 0x24, 0x21, 0xf9, 0x54, 0x14, 0x18, 0x9e, 0x3f, 0xe4, 0x29, 0x00, 0x12, 0x0e, 0xb0, 0x28, 0x50, - 0x3c, 0x60, 0x50, 0x85, 0xf4, 0x7f, 0xb8, 0x3f, 0xf3, 0xf8, 0x83, 0xe0, 0x00, 0x38, 0x6e, 0x0c, - 0xc3, 0xf2, 0x2f, 0x94, 0x09, 0x07, 0xc7, 0xf7, 0x3f, 0xfe, 0x0d, 0xc4, 0x00, 0xfc, 0x4c, 0x05, - 0x86, 0x15, 0x23, 0x92, 0x03, 0xe7, 0xf9, 0x80, 0x0f, 0x97, 0x52, 0x0c, 0x2f, 0xb1, 0xf8, 0xe3, - 0x01, 0xf3, 0x82, 0x27, 0x8d, 0xe6, 0x41, 0x1c, 0x17, 0xcf, 0xfc, 0x3e, 0x64, 0xf8, -}; -const uint8_t* _I_Splash_128x64[] = {_I_Splash_128x64_0}; -const Icon I_Splash_128x64 = - {.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_Splash_128x64}; - -/* -const uint8_t _I_BadEnd_128x64_0[] = { - 0x01, 0x00, 0xDF, 0x01, 0x00, 0x2c, 0x12, 0x01, 0x02, 0x80, 0x40, 0x70, 0x10, 0x0a, 0x04, 0x02, - 0x41, 0x3e, 0xcf, 0x63, 0xfb, 0xfe, 0xc8, 0x18, 0x3e, 0x6f, 0xdb, 0xfc, 0xf8, 0x3c, 0x60, 0xe0, - 0xf9, 0xb3, 0x6c, 0xf3, 0x3c, 0x1b, 0x6c, 0x18, 0x5f, 0x40, 0xf1, 0xe7, 0xdb, 0xc1, 0xf4, 0x2f, - 0x10, 0x78, 0xdb, 0xbc, 0xdf, 0xf0, 0x04, 0x59, 0x81, 0xe3, 0xc1, 0xb6, 0x41, 0x83, 0xd1, 0x00, - 0xbf, 0x6c, 0xc9, 0xe6, 0x0f, 0x91, 0xf8, 0x9b, 0xcc, 0x1f, 0x20, 0x06, 0x07, 0xf8, 0x3e, 0x0b, - 0x32, 0x00, 0x50, 0x88, 0xc4, 0x20, 0x10, 0x85, 0xfd, 0x03, 0xfc, 0x1f, 0xe0, 0xff, 0x07, 0xf9, - 0x7f, 0xc3, 0xdc, 0x89, 0x10, 0x7d, 0x00, 0x04, 0x1f, 0xe0, 0xfd, 0xfc, 0x40, 0xc1, 0xfb, 0x07, - 0x8e, 0x2f, 0xf3, 0x9f, 0x00, 0xb0, 0x7f, 0x97, 0xf6, 0x0a, 0x11, 0x10, 0xa3, 0xec, 0x10, 0x21, - 0x32, 0x07, 0xd0, 0x18, 0x40, 0xa2, 0x0f, 0xb0, 0x20, 0x81, 0xc4, 0x1f, 0xeb, 0xfa, 0xbf, 0x84, - 0x86, 0x01, 0xc8, 0x5f, 0xd0, 0x0c, 0x81, 0xe2, 0x05, 0x10, 0x7e, 0xdc, 0xc1, 0xf5, 0x01, 0xe0, - 0x41, 0xf2, 0x17, 0xf0, 0x7d, 0xaf, 0x0a, 0x7e, 0x0f, 0xbf, 0x84, 0x7f, 0x21, 0x1f, 0x2b, 0x8e, - 0x3c, 0xbe, 0xd3, 0xf0, 0x78, 0xc4, 0xfa, 0x0b, 0xf2, 0x00, 0x08, 0x81, 0xa1, 0xf3, 0x08, 0x9f, - 0xc0, 0x1e, 0x57, 0x00, 0x7b, 0x60, 0x60, 0x3e, 0x08, 0x4f, 0x80, 0x1e, 0x59, 0x05, 0xc1, 0x03, - 0xce, 0xc3, 0x00, 0x2f, 0x88, 0x3c, 0xe2, 0x10, 0x20, 0x78, 0xbd, 0xc6, 0xff, 0x7c, 0x8c, 0x0e, - 0x48, 0x1e, 0x90, 0x48, 0x47, 0xe2, 0x06, 0x1b, 0x1e, 0x3c, 0x1c, 0x1e, 0x80, 0x01, 0x93, 0xad, - 0x06, 0x1e, 0x0a, 0x28, 0x04, 0x18, 0x1e, 0x81, 0xe1, 0x90, 0x20, 0x46, 0x49, 0xa9, 0x91, 0x3e, - 0x46, 0xf8, 0x0f, 0xac, 0x48, 0x3c, 0xb0, 0x82, 0x52, 0x07, 0xa1, 0x08, 0x43, 0xe5, 0x72, 0x93, - 0x41, 0x7e, 0x01, 0x01, 0x07, 0xc7, 0x8a, 0x97, 0xa9, 0x39, 0x88, 0xa0, 0x7f, 0x00, 0xf2, 0x08, - 0x0c, 0x03, 0x25, 0x54, 0x88, 0xe9, 0x66, 0x11, 0xc2, 0x99, 0x9e, 0x07, 0xff, 0x13, 0x90, 0x7f, - 0xb2, 0x60, 0xf2, 0xaa, 0x79, 0x1b, 0xe5, 0x01, 0xfe, 0x1f, 0xca, 0x41, 0x08, 0xb0, 0xd4, 0xe2, - 0x33, 0x9c, 0x9f, 0x13, 0xff, 0x07, 0xc0, 0x0c, 0x04, 0x1e, 0x54, 0x08, 0x40, 0x64, 0x80, 0x03, - 0x84, 0xff, 0xc0, 0x68, 0x10, 0x0f, 0x80, 0x3d, 0x13, 0xc2, 0x00, 0x28, 0x25, 0xfa, 0x00, 0x0f, - 0x76, 0x60, 0x83, 0xcc, 0x04, 0x20, 0xc1, 0x07, 0xaf, 0xc8, 0x52, 0x52, 0x00, 0x7a, 0x2f, 0xcc, - 0x16, 0x31, 0x30, 0x49, 0x48, 0x17, 0xe5, 0x20, 0xc0, 0x23, 0xce, 0x81, 0x80, 0x88, 0xe6, 0x24, - 0x7c, 0x69, 0xc0, 0xd0, 0xa2, 0x1c, 0x00, 0x79, 0x85, 0x07, 0xe3, 0xa4, 0xb0, 0x4a, 0x64, 0xa0, - 0xf3, 0x57, 0x9d, 0x82, 0x01, 0x80, 0x84, 0x54, 0xb2, 0x19, 0x48, 0x91, 0x90, 0xa2, 0x1f, 0x00, - 0x79, 0x0f, 0x87, 0x80, 0x0f, 0x44, 0x21, 0x03, 0xd0, 0x3e, 0x26, 0x01, 0xa6, 0x44, 0x2c, 0x79, - 0xc0, 0x79, 0xb3, 0xc4, 0xbe, 0x5e, 0x01, 0x08, 0x80, 0x09, 0x56, 0x20, 0x01, 0x98, 0x03, 0xc4, - 0xfe, 0x51, 0x0b, 0xf8, 0x3c, 0xf8, 0x00, 0x32, 0x9c, 0x7f, 0x01, 0xe8, 0x1f, 0x40, 0x21, 0xd7, - 0x81, 0xfb, 0x80, 0xcf, 0x8f, 0x44, 0x1e, 0x7c, 0x88, 0x38, 0x28, 0x70, 0xe4, 0x92, 0xff, 0xc7, - 0xef, 0x1f, 0x80, -}; -const uint8_t* _I_BadEnd_128x64[] = {_I_BadEnd_128x64_0}; -const Icon I_BadEnd_128x64 = - {.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_BadEnd_128x64}; -*/ /* space savings until external apps are possible */ -const uint8_t _I_Hand_12x10_0[] = { - 0x01, 0x00, 0x11, 0x00, 0x8c, 0x40, 0x25, 0x00, 0x16, 0xb4, 0x40, - 0x35, 0x10, 0x1d, 0x5c, 0x1b, 0x5b, 0x0a, 0x84, 0xc2, 0x80, -}; -const uint8_t* _I_Hand_12x10[] = {_I_Hand_12x10_0}; -const Icon I_Hand_12x10 = - {.width = 12, .height = 10, .frame_count = 1, .frame_rate = 0, .frames = _I_Hand_12x10}; - -const uint8_t _I_CardBack_22x35_0[] = { - 0x01, 0x00, 0x23, 0x00, 0xfe, 0x7f, 0xe1, 0xf0, 0x28, 0x04, 0x43, 0xe3, 0xff, - 0x91, 0xea, 0x75, 0x52, 0x6a, 0xad, 0x56, 0x5b, 0xad, 0xd5, 0x4a, 0x80, 0xbe, - 0x05, 0xf0, 0x2f, 0x81, 0x7c, 0x0b, 0x45, 0x32, 0x2c, 0x91, 0x7c, 0x8c, 0xa4, -}; -const uint8_t* _I_CardBack_22x35[] = {_I_CardBack_22x35_0}; -const Icon I_CardBack_22x35 = - {.width = 22, .height = 35, .frame_count = 1, .frame_rate = 0, .frames = _I_CardBack_22x35}; - -//uncompressed but lol -const uint8_t _I_club_7x8_0[] = {0x00, 0x08, 0x1c, 0x1c, 0x6b, 0x7f, 0x36, 0x08, 0x1c}; -const uint8_t* _I_club_7x8[] = {_I_club_7x8_0}; -const Icon I_club_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_club_7x8}; - -//uncompressed but lol -const uint8_t _I_diamond_7x8_0[] = {0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08}; -const uint8_t* _I_diamond_7x8[] = {_I_diamond_7x8_0}; -const Icon I_diamond_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_diamond_7x8}; - -//uncompressed -const uint8_t _I_hearts_7x8_0[] = {0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08}; -const uint8_t* _I_hearts_7x8[] = {_I_hearts_7x8_0}; -const Icon I_hearts_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_hearts_7x8}; - -//uncompressed -const uint8_t _I_spade_7x8_0[] = {0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x36, 0x08, 0x1c}; -const uint8_t* _I_spade_7x8[] = {_I_spade_7x8_0}; -const Icon I_spade_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_spade_7x8}; - -// They only included Numeric Profont22 glyphs and I don't want to fuck up the font embeds right now sooo.. - -const uint8_t _I_King_7x8_0[] = { - 0x01, 0x00, 0x1a, 0x00, 0xc1, 0xc0, 0xf8, 0x70, 0x1f, 0x1c, 0x02, 0xe7, 0x00, 0x9d, 0xc0, - 0x23, 0xf0, 0x08, 0x78, 0x0c, 0x80, 0xe2, 0x0b, 0x10, 0x78, 0x84, 0xc4, 0x2e, 0x20, 0x01, -}; -const uint8_t* _I_King_7x8[] = {_I_King_7x8_0}; -const Icon I_King_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_King_7x8}; - -const uint8_t _I_Queen_7x8_0[] = { - 0x01, 0x00, 0x13, 0x00, 0xfe, 0x40, 0x3f, 0xd0, 0x1c, 0x3c, 0x0c, 0x01, - 0x76, 0x38, 0x1f, 0x8e, 0x07, 0xc7, 0x81, 0x85, 0x47, 0xf9, 0x01, -}; -const uint8_t* _I_Queen_7x8[] = {_I_Queen_7x8_0}; -const Icon I_Queen_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Queen_7x8}; - -const uint8_t _I_Jack_7x8_0[] = { - 0x01, - 0x00, - 0x0D, - 0x00, - 0x80, - 0x40, - 0xc0, - 0x3a, - 0x00, - 0x5c, - 0x3c, - 0x0f, - 0xfd, - 0x01, - 0xfe, - 0x40, - 0x00, -}; -const uint8_t* _I_Jack_7x8[] = {_I_Jack_7x8_0}; -const Icon I_Jack_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Jack_7x8}; - -const uint8_t _I_Ace_7x8_0[] = { - 0x01, 0x00, 0x13, 0x00, 0x98, 0x40, 0x2f, 0x00, 0x12, 0xe6, 0x00, 0x4b, - 0x0d, 0x01, 0x00, 0x8c, 0x0e, 0x07, 0xff, 0x00, 0x90, 0x01, 0xc0, -}; -const uint8_t* _I_Ace_7x8[] = {_I_Ace_7x8_0}; -const Icon I_Ace_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Ace_7x8}; - -const uint8_t _I_Ten_7x8_0[] = { - 0x01, 0x00, 0x29, 0x00, 0x86, 0x7f, 0x00, 0x43, 0xfe, 0x80, 0xc3, 0xf0, 0xf0, 0x38, 0x7e, - 0x0e, 0x07, 0x0c, 0xe1, 0x80, 0x87, 0xc6, 0x02, 0x1b, 0x98, 0x08, 0x67, 0x60, 0x21, 0x8f, - 0x80, 0x86, 0x1e, 0x02, 0x18, 0x38, 0x08, 0x43, 0x43, 0x7f, 0x10, 0x0d, 0xfc, 0x4c, 0x20, -}; -const uint8_t* _I_Ten_7x8[] = {_I_Ten_7x8_0}; -const Icon I_Ten_7x8 = - {.width = 18, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Ten_7x8}; - -const Icon card_suit[4] = {I_diamond_7x8, I_club_7x8, I_hearts_7x8, I_spade_7x8}; - -const Icon card_face[5] = {I_Ten_7x8, I_Jack_7x8, I_Queen_7x8, I_King_7x8, I_Ace_7x8}; - -/* Sanity check: check that there are no duplicate cards in hand */ - -static void playcard(PokerPlayer* app) { - int i, c, crd; - - int hold[5]; - hold[5] = 2; - // int digit; - c = 1; - c++; - c = hold[5]; /* FIX for unused-but-set-variable */ - /* initialize deck */ - for(i = 0; i < 52; i++) deck[i].gone = 0; - - /* initialize hold[] */ - for(i = 0; i < 5; i++) hold[i] = 1; - - /* app->score -= bet; */ - if(app->score > app->highscore) { - app->highscore = app->score; - } /* record high water mark */ - - for(i = 0; i < 5; i++) { - /* find a card not already dealt */ - do crd = random() % 52; - while(deck[crd].gone); - hold[i] = 1; - deck[crd].gone = 1; - if(!app->held[i]) { - app->hand[i] = deck[crd]; - } - } -} - -static int check_for_dupes(PokerPlayer* app) { - int i, j; - - for(i = 0; i < 5; i++) { - for(j = i + 1; j < 5; j++) { - if(app->hand[i].index == app->hand[j].index && app->hand[i].suit == app->hand[j].suit) - return 0; - } - } - - return 1; -} - -/* Functions that recognize winning hands */ - -/* - Flush: - returns 1 if the sorted hand is a flush -*/ - -static int flush(PokerPlayer* app) { - if(app->shand[0].suit == app->shand[1].suit && app->shand[1].suit == app->shand[2].suit && - app->shand[2].suit == app->shand[3].suit && app->shand[3].suit == app->shand[4].suit) - return 1; - - return 0; -} - -/* - Straight: - returns 1 if the sorted hand is a straight -*/ - -static int straight(PokerPlayer* app) { - if(app->shand[1].index == app->shand[0].index + 1 && - app->shand[2].index == app->shand[1].index + 1 && - app->shand[3].index == app->shand[2].index + 1 && - app->shand[4].index == app->shand[3].index + 1) - return 1; - - /* Ace low straight: Ace, 2, 3, 4, 5 */ - - if(app->shand[4].index == 13 && app->shand[0].index == 1 && app->shand[1].index == 2 && - app->shand[2].index == 3 && app->shand[3].index == 4) - return 1; - - return 0; -} - -/* - Four of a kind: - the middle 3 all match, and the first or last matches those -*/ - -static int four(PokerPlayer* app) { - if((app->shand[1].index == app->shand[2].index && - app->shand[2].index == app->shand[3].index) && - (app->shand[0].index == app->shand[2].index || app->shand[4].index == app->shand[2].index)) - return 1; - - return 0; -} - -/* - Full house: - 3 of a kind and a pair -*/ - -static int full(PokerPlayer* app) { - if(app->shand[0].index == app->shand[1].index && - (app->shand[2].index == app->shand[3].index && app->shand[3].index == app->shand[4].index)) - return 1; - - if(app->shand[3].index == app->shand[4].index && - (app->shand[0].index == app->shand[1].index && app->shand[1].index == app->shand[2].index)) - return 1; - - return 0; -} - -/* - Three of a kind: - it can appear 3 ways -*/ - -static int three(PokerPlayer* app) { - if(app->shand[0].index == app->shand[1].index && app->shand[1].index == app->shand[2].index) - return 1; - - if(app->shand[1].index == app->shand[2].index && app->shand[2].index == app->shand[3].index) - return 1; - - if(app->shand[2].index == app->shand[3].index && app->shand[3].index == app->shand[4].index) - return 1; - - return 0; -} - -/* - Two pair: - it can appear in 3 ways -*/ - -static int twopair(PokerPlayer* app) { - if(((app->shand[0].index == app->shand[1].index) && - (app->shand[2].index == app->shand[3].index)) || - ((app->shand[0].index == app->shand[1].index) && - (app->shand[3].index == app->shand[4].index)) || - ((app->shand[1].index == app->shand[2].index) && - (app->shand[3].index == app->shand[4].index))) - return 1; - - return 0; -} - -/* - Two of a kind (pair), jacks or better - or if the game is Tens or Better, 10s or better. -*/ - -static int two(PokerPlayer* app) { - int min = 10; - - if(app->GameType == 1) min = 9; - - if(app->shand[0].index == app->shand[1].index && app->shand[1].index >= min) return 1; - if(app->shand[1].index == app->shand[2].index && app->shand[2].index >= min) return 1; - if(app->shand[2].index == app->shand[3].index && app->shand[3].index >= min) return 1; - if(app->shand[3].index == app->shand[4].index && app->shand[4].index >= min) return 1; - - return 0; -} - -static int paytable[10] = { - 800, /* royal flush: 800 */ - 50, /* straight flush: 50 */ - 25, /* 4 of a kind: 25 */ - 9, /* full house: 9 */ - 6, /* flush: 6 */ - 4, /* straight: 4 */ - 3, /* 3 of a kind: 3 */ - 2, /* two pair: 2 */ - 1, /* jacks or better: 1 */ - 0 /* nothing */ -}; - -static const char* poker_handname[10] = { - "Royal Flush", - "Straight Flush", - "Four of a Kind", - "Full House", - "Flush", - "Straight", - "Three of a Kind", - "Two Pair", - "Pair", - "Nothing", -}; - -static int recognize(PokerPlayer* app) { - int i, j, f = 0; - int min = 100; - PokerPlayer_card tmp[5]; - int st = 0, fl = 0; - - /* Sort hand into sorted hand (app->shand) */ - - /* make copy of hand */ - for(i = 0; i < 5; i++) tmp[i] = app->hand[i]; - - for(i = 0; i < 5; i++) { - /* put lowest card in hand into next place in app->shand */ - - for(j = 0; j < 5; j++) - if(tmp[j].index <= min) { - min = tmp[j].index; - f = j; - } - - app->shand[i] = tmp[f]; - tmp[f].index = 100; /* larger than any card */ - min = 100; - } - - /* royal and straight flushes, strait, and flush */ - - fl = flush(app); - st = straight(app); - - if(st && fl && app->shand[0].index == 9) return 0; - if(st && fl) return 1; - if(four(app)) return 2; - if(full(app)) return 3; - if(fl) return 4; - if(st) return 5; - if(three(app)) return 6; - if(twopair(app)) return 7; - if(two(app)) return 8; - - /* Nothing */ - - return 9; -} - -void poker_draw_callback(Canvas* canvas, void* ctx) { - PokerPlayer* poker_player = ctx; - furi_check(furi_mutex_acquire(poker_player->model_mutex, FuriWaitForever) == FuriStatusOk); - canvas_clear(canvas); - char buffer[30]; - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - - /* Magic Begins */ - - /* Status Info */ - if(poker_player->GameState != 0 && poker_player->GameState != 4) { - snprintf(buffer, sizeof(buffer), "%d", poker_player->score); - canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, buffer); - } - - /* Start of game. Cards are face down, bet can be changed */ - if(poker_player->GameState == 1) { - snprintf(buffer, sizeof(buffer), "Bet:%d", poker_player->bet); - canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, buffer); - snprintf(buffer, sizeof(buffer), "<*> Place Bet"); - canvas_draw_str_aligned(canvas, 0, 9, AlignLeft, AlignTop, buffer); - - for(int i = 0; i < 5; ++i) { - canvas_draw_icon(canvas, 5 + (i * 24), 18, &I_CardBack_22x35); /* 5, 29, 53, 77, 101 */ - } - } - /* Cards are turned face up. Bet is deducted and put in th pot. Show the selector hand */ - else if(poker_player->GameState == 2 || poker_player->GameState == 3) { - snprintf(buffer, sizeof(buffer), "Pot:%d", poker_player->bet); - canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, buffer); - snprintf(buffer, sizeof(buffer), "<*> Select Hold"); - canvas_draw_str_aligned(canvas, 0, 9, AlignLeft, AlignTop, buffer); - - /* Normal or inverse to indicate selection - cards*/ - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_draw_rbox(canvas, 5 + (i * 24), 18, 22, 35, 3) : - canvas_draw_rframe(canvas, 5 + (i * 24), 18, 22, 35, 3); - } - - /* Normal or inverse to indicate selection - card suit and value */ - - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_set_color(canvas, ColorWhite) : - canvas_set_color(canvas, ColorBlack); - - canvas_draw_icon(canvas, 18 + (i * 24), 43, &card_suit[poker_player->hand[i].suit]); - } - - /* Card Value. Profont_22 does not include letters (AJQK), and "10" is too big. These are bitmaps. */ - canvas_set_font(canvas, FontBigNumbers); - - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_set_color(canvas, ColorWhite) : - canvas_set_color(canvas, ColorBlack); - if(poker_player->hand[i].index >= 1 && poker_player->hand[i].index <= 8) { - snprintf(buffer, sizeof(buffer), "%s", poker_player->hand[i].sym); - canvas_draw_str_aligned(canvas, 8 + (i * 24), 21, AlignLeft, AlignTop, buffer); - } else { - if(poker_player->hand[i].index >= 9 && poker_player->hand[i].index <= 13) { - canvas_draw_icon( - canvas, 7 + (i * 24), 21, &card_face[poker_player->hand[i].index - 9]); - } - } - } - - /* Draw the Select hand */ - if(poker_player->GameState == 2) { - canvas_set_color(canvas, ColorBlack); - - canvas_draw_icon(canvas, 11 + (poker_player->selected * 24), 54, &I_Hand_12x10); - } - } // GameState 2 or 3 - - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - if(poker_player->GameState == 3) { - snprintf( - buffer, - sizeof(buffer), - "%s:%ix", - poker_handname[recognize(poker_player)], - paytable[recognize(poker_player)]); - canvas_draw_str_aligned(canvas, 63, 61, AlignCenter, AlignBottom, buffer); - } - if(poker_player->GameState == 0) { - canvas_draw_icon(canvas, 0, 0, &I_Splash_128x64); /* Initial launch */ - } - if(poker_player->GameState == 4) { - /* canvas_draw_icon(canvas, 0, 0, &I_BadEnd_128x64); Just Lost The Game - disabled for now :( */ - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - snprintf(buffer, sizeof(buffer), "%s", "You have run out of money!"); - canvas_draw_str_aligned(canvas, 63, 22, AlignCenter, AlignCenter, buffer); - snprintf(buffer, sizeof(buffer), "%s", "At one point, you had"); - canvas_draw_str_aligned(canvas, 63, 32, AlignCenter, AlignCenter, buffer); - snprintf(buffer, sizeof(buffer), "%d dollars", poker_player->highscore); - canvas_draw_str_aligned(canvas, 63, 42, AlignCenter, AlignCenter, buffer); - } - - furi_mutex_release(poker_player->model_mutex); -} - -void poker_input_callback(InputEvent* input, void* ctx) { - PokerPlayer* poker_player = ctx; - furi_message_queue_put(poker_player->event_queue, input, FuriWaitForever); -} - -PokerPlayer* poker_player_alloc() { - PokerPlayer* poker_player = malloc(sizeof(PokerPlayer)); - - poker_player->score = 1000; - poker_player->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - poker_player->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - poker_player->view_port = view_port_alloc(); - poker_player->selected = 0; - poker_player->GameState = 0; - poker_player->bet = 10; - poker_player->minbet = 10; - poker_player->highscore = 1000; - - playcard( - poker_player); /* Get things rolling before the player gets into the game. This will preload the hand. */ - view_port_draw_callback_set(poker_player->view_port, poker_draw_callback, poker_player); - - view_port_input_callback_set(poker_player->view_port, poker_input_callback, poker_player); - - poker_player->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(poker_player->gui, poker_player->view_port, GuiLayerFullscreen); - - return poker_player; -} - -void poker_player_free(PokerPlayer* poker_player) { - view_port_enabled_set(poker_player->view_port, false); - gui_remove_view_port(poker_player->gui, poker_player->view_port); - furi_record_close(RECORD_GUI); - view_port_free(poker_player->view_port); - furi_message_queue_free(poker_player->event_queue); - furi_mutex_free(poker_player->model_mutex); - - free(poker_player); -} - -int32_t video_poker_app(void* p) { - UNUSED(p); - PokerPlayer* poker_player = poker_player_alloc(); - - InputEvent event; - for(bool processing = true; processing;) { - FuriStatus status = furi_message_queue_get(poker_player->event_queue, &event, 100); - furi_check(furi_mutex_acquire(poker_player->model_mutex, FuriWaitForever) == FuriStatusOk); - if(status == FuriStatusOk) { - if(event.type == InputTypePress) { - switch(event.key) { - case InputKeyUp: - Shake(); - break; - case InputKeyDown: - if(poker_player->GameState == 2) { - playcard(poker_player); - if(check_for_dupes(poker_player) == 0) { - playcard(poker_player); - } - - poker_player->GameState = 3; - } - break; - case InputKeyLeft: - if(poker_player->GameState == 1) { - if(poker_player->bet >= poker_player->minbet + 10) { - poker_player->bet -= 10; - } - } else if(poker_player->selected > 0 && poker_player->GameState == 2) { - poker_player->selected--; - } // Move hand left/right - else if(poker_player->selected == 0 && poker_player->GameState == 2) { - poker_player->selected = 4; //wraparound - } - break; - case InputKeyRight: - if(poker_player->GameState == 1) { - if(poker_player->bet < poker_player->score + 10) { - poker_player->bet += 10; - } - } - if(poker_player->selected < 4 && poker_player->GameState == 2) { - poker_player->selected++; - } // Move hand left/right - else if(poker_player->selected == 4 && poker_player->GameState == 2) { - poker_player->selected = 0; //wraparound - } - break; - case InputKeyOk: - /* close splash screen */ - if(poker_player->GameState == 0) { - poker_player->GameState = 1; - } else if(poker_player->GameState == 1) { - /* Pledge bet. Bet is subtracted here. Original code subtracts it during playcard - but playcard is called multiple times which would otherwise subtract bet - multiple times */ - poker_player->score -= poker_player->bet; - poker_player->GameState = 2; - } else if(poker_player->GameState == 2) { - /* Select or un-select card to be held */ - poker_player->held[poker_player->selected] = - !poker_player - ->held[poker_player->selected]; //cursed and bad pls replace - } else if(poker_player->GameState == 3) { - /* accept your fate */ - if(recognize(poker_player) != 9) { - poker_player->score += - poker_player->bet * paytable[recognize(poker_player)]; - } - poker_player->GameState = 1; - if(poker_player->bet > poker_player->score) { - poker_player->bet = poker_player->score; - } - poker_player->held[0] = 0; - poker_player->held[1] = 0; - poker_player->held[2] = 0; - poker_player->held[3] = 0; - poker_player->held[4] = 0; - if(poker_player->score <= 0) { - /* lost the game */ - poker_player->GameState = 4; - } - playcard(poker_player); // shuffle shuffle - } else if(poker_player->GameState == 4) { - /* escape the summary, return to splash */ - Shake(); - poker_player->selected = 0; - poker_player->GameState = 0; - poker_player->bet = 10; - poker_player->minbet = 10; - poker_player->highscore = 1000; - poker_player->score = 1000; - poker_player->GameState = 0; - } - break; - case InputKeyBack: - /* if game is not over, we should store the game state. */ - processing = false; - break; - default: - break; - } - } - } - furi_mutex_release(poker_player->model_mutex); - view_port_update(poker_player->view_port); - } - - poker_player_free(poker_player); - return 0; -} diff --git a/applications/external/videopoker/pokerIcon.png b/applications/external/videopoker/pokerIcon.png deleted file mode 100644 index db5507d0c..000000000 Binary files a/applications/external/videopoker/pokerIcon.png and /dev/null differ diff --git a/applications/external/zombiez/application.fam b/applications/external/zombiez/application.fam deleted file mode 100644 index 898488826..000000000 --- a/applications/external/zombiez/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="zombiez", - name="Zombiez", - apptype=FlipperAppType.EXTERNAL, - entry_point="zombiez_game_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="zombie_10px.png", - fap_category="Games", - fap_author="@DevMilanIan & @xMasterX, (original By @Dooskington)", - fap_version="1.0", - fap_description="Defend your walls from the zombies", -) diff --git a/applications/external/zombiez/zombie_10px.png b/applications/external/zombiez/zombie_10px.png deleted file mode 100644 index 37363ec04..000000000 Binary files a/applications/external/zombiez/zombie_10px.png and /dev/null differ diff --git a/applications/external/zombiez/zombiez.c b/applications/external/zombiez/zombiez.c deleted file mode 100644 index a9bf74f7a..000000000 --- a/applications/external/zombiez/zombiez.c +++ /dev/null @@ -1,402 +0,0 @@ -#include -#include -#include -#include -#include - -//ORIGINAL REPO: https://github.com/Dooskington/flipperzero-zombiez -//AUTHORS: https://github.com/Dooskington | https://github.com/DevMilanIan - -#include "zombiez.h" - -#define ZOMBIES_MAX 3 -#define ZOMBIES_WIDTH 5 -#define ZOMBIES_HEIGHT 8 -#define PROJECTILES_MAX 10 - -#define MIN_Y 5 -#define MAX_Y 58 -#define WALL_X 16 -#define PLAYER_START_X 8 -#define PLAYER_START_Y (MAX_Y - MIN_Y) / 2 - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef enum { GameStatePlaying, GameStateGameOver } GameState; - -typedef struct { - int x; - int y; -} Point; - -typedef struct { - Point position; - int hp; -} Player; - -typedef struct { - Point position; - int hp; -} Zombie; - -typedef struct { - Point position; -} Projectile; - -typedef struct { - FuriMutex* mutex; - GameState game_state; - Player player; - - size_t zombies_count; - Zombie* zombies[ZOMBIES_MAX]; - - size_t projectiles_count; - Projectile* projectiles[PROJECTILES_MAX]; - - uint16_t score; - bool input_shoot; -} PluginState; - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - plugin_state->player.position.x, - plugin_state->player.position.y, - AlignCenter, - AlignCenter, - "@"); - - canvas_draw_line(canvas, WALL_X, 0, WALL_X, 64); - canvas_draw_line(canvas, WALL_X + 2, 4, WALL_X + 2, 59); - - for(int i = 0; i < PROJECTILES_MAX; ++i) { - Projectile* p = plugin_state->projectiles[i]; - if(p != NULL) { - canvas_draw_disc(canvas, p->position.x, p->position.y, 3); - } - } - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - Zombie* z = plugin_state->zombies[i]; - if(z != NULL) { - for(int h = 0; h < ZOMBIES_HEIGHT; h++) { - for(int w = 0; w < ZOMBIES_WIDTH; w++) { - // Switch animation - int zIdx = 0; - if(z->position.x % 2 == 0) { - zIdx = 1; - } - - // Draw zombie pixels - if(zombie_array[zIdx][h][w] == 1) { - int x = z->position.x + w; - int y = z->position.y + h; - - canvas_draw_dot(canvas, x, y); - } - } - } - } - } - - int heart; - if((plugin_state->player.hp - 10) > 5) { // 16, 17, 18, 19, 20 - heart = 0; - } else if((plugin_state->player.hp - 5) > 5) { // 11, 12, 13, 14, 15 - heart = 1; - } else if((plugin_state->player.hp - 3) > 2) { // 6, 7, 8, 9, 10 - heart = 2; - } else if(plugin_state->player.hp > 0) { // 1, 2, 3, 4, 5 - heart = 3; - } else { // 0 - heart = 4; - } - // visual representation of health - for(int h = 0; h < 5; h++) { - for(int w = 0; w < 5; w++) { - if(heart_array[heart][h][w] == 1) { - int x = 124 - w; - int y = 56 + h; - - canvas_draw_dot(canvas, x, y); - } - } - } - - // buffer hp + score - char hpBuffer[8]; - char scoreBuffer[14]; - - if(plugin_state->game_state == GameStatePlaying) { - // display ammo / reload - if(plugin_state->projectiles_count >= PROJECTILES_MAX) { - canvas_draw_str_aligned(canvas, 24, 10, AlignLeft, AlignCenter, "RELOAD"); - } else { - for(uint8_t i = 0; i < (PROJECTILES_MAX - plugin_state->projectiles_count); i++) { - canvas_draw_box(canvas, 24 + (4 * i), 6, 2, 4); - } - } - // display hp + score - snprintf(hpBuffer, sizeof(hpBuffer), "%u", plugin_state->player.hp); - canvas_draw_str_aligned(canvas, 118, 62, AlignRight, AlignBottom, hpBuffer); - - snprintf(scoreBuffer, sizeof(scoreBuffer), "%u", plugin_state->score); - canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, scoreBuffer); - } - // Game Over banner - if(plugin_state->game_state == GameStateGameOver) { - // Screen is 128x64 px - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 37, 31, "Game Over"); - - canvas_set_font(canvas, FontSecondary); - snprintf(scoreBuffer, sizeof(scoreBuffer), "Score: %u", plugin_state->score); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, scoreBuffer); - } - - //char* info = (char*)malloc(16 * sizeof(char)); - //asprintf(&info, "%d, %d", plugin_state->x, plugin_state->y); - //canvas_draw_str_aligned(canvas, 32, 16, AlignLeft, AlignBottom, info); - //free(info); - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tick(PluginState* const plugin_state) { - if(plugin_state->input_shoot && (plugin_state->projectiles_count < PROJECTILES_MAX)) { - Projectile* p = (Projectile*)malloc(sizeof(Projectile)); - p->position.x = plugin_state->player.position.x; - p->position.y = plugin_state->player.position.y; - - size_t idx = plugin_state->projectiles_count; - plugin_state->projectiles[idx] = p; - plugin_state->projectiles_count += 1; - } - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - if(!plugin_state->zombies[i]) { - Zombie* z = (Zombie*)malloc(sizeof(Zombie)); - //z->hp = 20; - z->position.x = 126; - z->position.y = MIN_Y + (rand() % (MAX_Y - MIN_Y)); - - plugin_state->zombies[i] = z; - plugin_state->zombies_count += 1; - } - } - - for(int i = 0; i < PROJECTILES_MAX; ++i) { - Projectile* p = plugin_state->projectiles[i]; - if(p != NULL) { - p->position.x += 2; - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - Zombie* z = plugin_state->zombies[i]; - if(z != NULL) { - if( // projectile close enough to zombie - (((z->position.x - p->position.x) <= 2) && - ((z->position.y - p->position.y) <= 4)) && - (((p->position.x - z->position.x) <= 2) && - ((p->position.y - z->position.y) <= 6))) { - //z->hp -= 5; - //if(z->hp <= 0) { - plugin_state->zombies_count -= 1; - free(z); - plugin_state->zombies[i] = NULL; - plugin_state->score++; - //if(plugin_state->score % 15 == 0) dolphin_deed(getRandomDeed()); - //} - } else if(z->position.x <= WALL_X && z->position.x > 0) { // zombie got to the wall - plugin_state->zombies_count -= 1; - free(z); - plugin_state->zombies[i] = NULL; - if(plugin_state->player.hp > 0) { - plugin_state->player.hp--; - } else { - plugin_state->game_state = GameStateGameOver; - } - } else { - if(furi_get_tick() % 2 == 0) z->position.x--; - } - } - } - - if(p->position.x >= 128) { - free(p); - plugin_state->projectiles[i] = NULL; - } - } - } - - plugin_state->input_shoot = false; -} - -static void timer_callback(void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - PluginEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void zombiez_state_init(PluginState* const plugin_state) { - plugin_state->player.position.x = PLAYER_START_X; - plugin_state->player.position.y = PLAYER_START_Y; - plugin_state->player.hp = 20; - - plugin_state->projectiles_count = 0; - plugin_state->zombies_count = 0; - plugin_state->score = 0; - - for(int i = 0; i < PROJECTILES_MAX; i++) { - plugin_state->projectiles[i] = NULL; - } - - for(int i = 0; i < ZOMBIES_MAX; i++) { - plugin_state->zombies[i] = NULL; - } - - plugin_state->game_state = GameStatePlaying; - plugin_state->input_shoot = false; -} - -int32_t zombiez_game_app(void* p) { - UNUSED(p); - uint32_t return_code = 0; - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - zombiez_state_init(plugin_state); - - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("Zombiez", "cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - PluginEvent event; - bool isRunning = true; - while(isRunning) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(plugin_state->player.position.y > MIN_Y && - plugin_state->game_state == GameStatePlaying) { - plugin_state->player.position.y--; - } - break; - case InputKeyDown: - if(plugin_state->player.position.y < MAX_Y && - plugin_state->game_state == GameStatePlaying) { - plugin_state->player.position.y++; - } - break; - case InputKeyOk: - if(plugin_state->projectiles_count < PROJECTILES_MAX && - plugin_state->game_state == GameStatePlaying) { - plugin_state->input_shoot = true; - } - break; - case InputKeyBack: - break; - default: - break; - } - } else if( - event.input.type == InputTypeRepeat && - plugin_state->game_state == GameStatePlaying) { - switch(event.input.key) { - case InputKeyUp: - if(plugin_state->player.position.y > (MIN_Y + 1)) { - plugin_state->player.position.y -= 4; - } - break; - case InputKeyDown: - if(plugin_state->player.position.y < (MAX_Y - 1)) { - plugin_state->player.position.y += 4; - } - break; - default: - break; - } - } else if(event.input.type == InputTypeLong) { - if(event.input.key == InputKeyOk) { - if(plugin_state->game_state == GameStateGameOver) { - zombiez_state_init(plugin_state); - } else if(plugin_state->projectiles_count >= PROJECTILES_MAX) { - plugin_state->projectiles_count = 0; - plugin_state->player.hp++; - } - } else if(event.input.key == InputKeyBack) { - isRunning = false; - } - } - } else if(event.type == EventTypeTick) { - tick(plugin_state); - } - } - - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(plugin_state->mutex); - -free_and_exit: - free(plugin_state); - furi_message_queue_free(event_queue); - - return return_code; -} \ No newline at end of file diff --git a/applications/external/zombiez/zombiez.h b/applications/external/zombiez/zombiez.h deleted file mode 100644 index eea71d707..000000000 --- a/applications/external/zombiez/zombiez.h +++ /dev/null @@ -1,62 +0,0 @@ -#include - -uint8_t zombie_array[2][8][5] = { - { - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - }, -}; - -uint8_t heart_array[5][5][5] = { - { - {0, 1, 0, 1, 0}, - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {1, 0, 0, 0, 1}, - {0, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 0, 1, 0}, - {1, 0, 0, 0, 1}, - }, -}; \ No newline at end of file