diff --git a/node/code/Makefile b/node/code/Makefile index eb56b25..2270021 100644 --- a/node/code/Makefile +++ b/node/code/Makefile @@ -58,7 +58,7 @@ ifndef CONFIG_LWM2M_SERVER_URI endif ##### /LWM2M ##### -CFLAGS += -DCONFIG_LWM2M_DEVICE_NAME=\""urn:t8i:dev:1"\" +CFLAGS += -DCONFIG_LWM2M_DEVICE_NAME=\""urn:t8i:dev:3"\" include $(RIOTBASE)/Makefile.include diff --git a/node/code/RIOT b/node/code/RIOT index 772ccb9..886c6a2 160000 --- a/node/code/RIOT +++ b/node/code/RIOT @@ -1 +1 @@ -Subproject commit 772ccb99542f13525053a6455d586667a82c2b9c +Subproject commit 886c6a27099bed0157a3bc21fbcd221778bf834d diff --git a/node/code/modules/display_handler/display_handler.c b/node/code/modules/display_handler/display_handler.c index 4eb4fd4..c9d7ebe 100644 --- a/node/code/modules/display_handler/display_handler.c +++ b/node/code/modules/display_handler/display_handler.c @@ -28,6 +28,8 @@ char display_thread_stack [DISPLAY_STACKSIZE]; +char game_thread_stack [DISPLAY_STACKSIZE]; + handler_result_t displayHandler_handleEvent(EVENT_T event){ char buf[100]; DEBUG("[DisplayHandler:handleEvent]\n"); @@ -49,7 +51,6 @@ handler_result_t displayHandler_handleEvent(EVENT_T event){ break; case BUTTON_DOWN_RELEASED: down_released(); - init_registered_pet(); break; case BUTTON_LEFT_PRESSED: left_pressed(); @@ -65,7 +66,6 @@ handler_result_t displayHandler_handleEvent(EVENT_T event){ break; case REGISTER_CODE: init_not_registered_code(get_register_code()); - //init_not_registered_code("Hallo Tom"); break; case REGISTERED: init_registered_no_pet(); @@ -79,6 +79,15 @@ handler_result_t displayHandler_handleEvent(EVENT_T event){ case INFO_PRESSED: get_pet_stats((char*)&buf); init_pet_stats((char*)&buf); + break; + case DEAD: + showDeadScreen(); + break; + case GAME_START: + DEBUG("[DisplayHandler:handleEvent]: GAME_START\n"); + thread_create(game_thread_stack, sizeof(game_thread_stack), + THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_WOUT_YIELD, game_loop, NULL, "Snake Game"); + break; default: break; } diff --git a/node/code/modules/display_handler/include/display_handler.h b/node/code/modules/display_handler/include/display_handler.h index 460f4ca..73ba3c0 100644 --- a/node/code/modules/display_handler/include/display_handler.h +++ b/node/code/modules/display_handler/include/display_handler.h @@ -37,4 +37,7 @@ void startDisplayThread(void); */ void display_init(void); + +void direction_handler(EVENT_T event); + #endif /* DISPLAY_HANDLER_T */ diff --git a/node/code/modules/display_handler/include/init_lvgl.h b/node/code/modules/display_handler/include/init_lvgl.h index d098f1a..8371b22 100644 --- a/node/code/modules/display_handler/include/init_lvgl.h +++ b/node/code/modules/display_handler/include/init_lvgl.h @@ -25,6 +25,9 @@ void change_top_bar_text(char* top_bar_text); void init_registered_no_pet(void); void init_registered_pet(void); void init_pet_stats(char* stats); +void showDeadScreen(void); + +void * game_loop(void * arg); #ifdef __cplusplus } diff --git a/node/code/modules/display_handler/init_lvgl.c b/node/code/modules/display_handler/init_lvgl.c index 5a8c8b6..2d1ebc8 100644 --- a/node/code/modules/display_handler/init_lvgl.c +++ b/node/code/modules/display_handler/init_lvgl.c @@ -28,12 +28,23 @@ #include "lvgl/src/core/lv_indev.h" #include "lvgl/src/hal/lv_hal_indev.h" #include "disp_dev.h" +#include "ztimer.h" #include "init_lvgl.h" #include "events.h" + +#define ENABLE_DEBUG 1 #include "debug.h" -lv_obj_t * roller1; +typedef enum { + UP, + DOWN, + LEFT, + RIGHT +} Direction; + +Direction direction; +lv_obj_t * screen; lv_obj_t * top_bar; lv_obj_t * center; @@ -86,7 +97,7 @@ void init_menu(void); //main here -static void menu_cb(lv_event_t * e){ +static void menu_cb(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_KEY) { @@ -167,6 +178,7 @@ void enter_released(void){ } void up_pressed(void){ + direction = UP; buttons[1].state = true; } @@ -175,6 +187,7 @@ void up_released(void){ } void down_pressed(void){ + direction = DOWN; buttons[2].state = true; } @@ -183,6 +196,7 @@ void down_released(void){ } void left_pressed(void){ + direction = LEFT; buttons[3].state = true; } @@ -191,6 +205,7 @@ void left_released(void){ } void right_pressed(void){ + direction = RIGHT; buttons[4].state = true; } @@ -220,7 +235,7 @@ void init_default_screen(char* top_bar_text){ lv_obj_t * screen = lv_obj_create(lv_scr_act()); lv_obj_clear_flag(screen,LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_size(screen, 320, 240); - lv_obj_add_style(screen,&style_base, LV_PART_MAIN); + lv_obj_add_style(screen, &style_base, LV_PART_MAIN); /* Style for top bar */ static lv_style_t style_top_bar; @@ -311,8 +326,6 @@ void init_not_registered(void){ wakeup_task = lv_timer_create(timer_cb, WAKEUP_TIME, NULL); } - - void init_not_registered_code(char *code){ // timer_deactivate(); lv_obj_clean(center); @@ -340,12 +353,14 @@ void init_not_registered_code(char *code){ } void init_registered_no_pet(void){ + init_default_screen("Pet Room"); lv_obj_clean(center); + init_menu(); } void init_registered_pet(void){ // timer_deactivate(); - lv_obj_clean(center); + lv_obj_clean(center); /* Style of the align */ static lv_style_t style_align; @@ -403,6 +418,8 @@ void init_pet_stats(char* stats){ } void init_menu(void){ + lv_obj_clean(bottom_bar); + current_img_index = 0; static lv_style_t style; lv_style_init(&style); lv_style_set_bg_opa(&style,LV_OPA_TRANSP); @@ -475,3 +492,191 @@ int init_lvgl(void) init_not_registered(); return 0; } + +void showDeadScreen(void){ + lv_obj_clean(center); + + lv_obj_t * dead_label = lv_label_create(center); + static lv_style_t style_label; + lv_style_init(&style_label); + lv_style_set_text_font(&style_label, &lv_font_montserrat_24); + lv_obj_add_style(dead_label, &style_label, LV_PART_MAIN); + + lv_label_set_text(dead_label, "Your pet is dead!"); + lv_obj_align(dead_label, LV_ALIGN_CENTER, 0, 0); +} + + +/****** + +for snake game + + +*******/ + +#define SNAKE_MAX_LENGTH 10 +#define SNAKE_START_LENGTH 3 +#define GRID_SIZE 30 +#define GRID_WIDTH (320 / GRID_SIZE) +#define GRID_HEIGHT (240 / GRID_SIZE) +#define SNAKE_SPEED 200 // Milliseconds + +int snake_speed = SNAKE_SPEED; + + +typedef struct { + int x; + int y; +} Point; + +static Point snake[SNAKE_MAX_LENGTH]; +static int snake_length; +static Point food; + +static lv_obj_t *snake_objs[SNAKE_MAX_LENGTH]; +static lv_obj_t *food_obj; + +void game_won(void) { + lv_obj_t *label = lv_label_create(screen); + snake_speed = SNAKE_SPEED; + lv_label_set_text(label, "You Win!"); + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); + ztimer_sleep(ZTIMER_SEC,3); + init_default_screen("Initializing ..."); + init_registered_pet(); + init_menu(); + trigger_event(GAME_FINISHED); +} + +void init_game(void) { + snake_length = SNAKE_START_LENGTH; + snake_speed = SNAKE_SPEED; + lv_obj_clean(lv_scr_act()); + screen = lv_obj_create(lv_scr_act()); + static lv_style_t style_base; + lv_style_init(&style_base); + lv_style_set_border_width(&style_base,0); + lv_style_set_pad_all(&style_base,0); + lv_obj_clear_flag(screen,LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_size(screen, 320, 240); + lv_obj_add_style(screen, &style_base, LV_PART_MAIN); + lv_obj_align(screen, LV_ALIGN_CENTER, 0, 0); + + static lv_style_t snake_style; + lv_style_init(&snake_style); + lv_style_set_bg_color(&snake_style, lv_color_hex(0x00FF00)); // Grün für die Schlange + + static lv_style_t food_style; + lv_style_init(&food_style); + lv_style_set_bg_color(&food_style, lv_color_hex(0xFF0000)); // Rot für das Essen + + + for (int i = 0; i < snake_length; i++) { + snake[i].x = GRID_WIDTH / 2 - i; + snake[i].y = GRID_HEIGHT / 2; + snake_objs[i] = lv_obj_create(screen); + lv_obj_set_size(snake_objs[i], GRID_SIZE, GRID_SIZE); + lv_obj_add_style(snake_objs[i], &snake_style, LV_PART_MAIN); + lv_obj_set_pos(snake_objs[i], snake[i].x * GRID_SIZE, snake[i].y * GRID_SIZE); + } + direction = RIGHT; + + // Place food + food.x = lv_rand(1, GRID_WIDTH-1); + food.y = lv_rand(1, GRID_HEIGHT-1); + food_obj = lv_obj_create(screen); + lv_obj_set_size(food_obj, GRID_SIZE, GRID_SIZE); + lv_obj_add_style(food_obj, &food_style, LV_PART_MAIN); + lv_obj_set_pos(food_obj, food.x * GRID_SIZE, food.y * GRID_SIZE); +} + +bool update_game(void) { + // Move snake body + for (int i = snake_length - 1; i > 0; i--) { + snake[i] = snake[i - 1]; + lv_obj_set_pos(snake_objs[i], snake[i].x * GRID_SIZE, snake[i].y * GRID_SIZE); + } + + // Move snake head + switch (direction) { + case UP: snake[0].y--; break; + case DOWN: snake[0].y++; break; + case LEFT: snake[0].x--; break; + case RIGHT: snake[0].x++; break; + } + + lv_obj_set_pos(snake_objs[0], snake[0].x * GRID_SIZE, snake[0].y * GRID_SIZE); + // DEBUG("x: %d, y: %d\n",snake[0].x * GRID_SIZE,snake[0].y * GRID_SIZE); + + // Check food collision + if (snake[0].x == food.x && snake[0].y == food.y) { + if (snake_length < SNAKE_MAX_LENGTH) { + snake_length++; + lv_obj_t *new_body_part = lv_obj_create(screen); + lv_obj_set_size(new_body_part, GRID_SIZE, GRID_SIZE); + static lv_style_t style; + lv_style_init(&style); + lv_style_set_bg_opa(&style, LV_OPA_50); + lv_style_set_bg_color(&style, lv_color_hex(0x00FF00)); // Grün für die Schlange + lv_obj_add_style(new_body_part, &style, LV_PART_MAIN); + + snake_objs[snake_length - 1] = new_body_part; + } + + food.x = lv_rand(0, GRID_WIDTH-1); + food.y = lv_rand(0, GRID_HEIGHT-1); + lv_obj_set_pos(food_obj, food.x * GRID_SIZE, food.y * GRID_SIZE); + snake_speed -= 10; + } + + // Check win condition + if (snake_length >= 10) { + game_won(); + return true; // Stop further updates if the game is won + } + + // Check wall collision + if (snake[0].x < 0 || snake[0].x >= GRID_WIDTH || snake[0].y < 0 || snake[0].y >= GRID_HEIGHT) { + // Game Over + init_game(); + } + + // Check self collision + for (int i = 1; i < snake_length; i++) { + if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) { + // Game Over + init_game(); + } + } + return false; +} + +void lv_tick_task(void *arg) { + (void)arg; + //lv_tick_inc(1); +} + + + +void *game_loop(void * arg) { + (void) arg; + init_game(); + + //Start game loop + while (1) { + if (update_game()) { + break; + } + lv_task_handler(); + ztimer_sleep(ZTIMER_MSEC, snake_speed); + } + game_won(); + return NULL; +} + +/****** + +for snake game + + +*******/ diff --git a/node/code/modules/fsm/fsm.c b/node/code/modules/fsm/fsm.c index b12e9a0..e6c7dc5 100644 --- a/node/code/modules/fsm/fsm.c +++ b/node/code/modules/fsm/fsm.c @@ -20,14 +20,20 @@ handler_result_t on_handler(EVENT_T event); void on_entry(void); handler_result_t off_handler(EVENT_T event); void off_entry(void); + handler_result_t unregistered_handler(EVENT_T event); void unregistered_entry(void); handler_result_t userLinked_handler(EVENT_T event); void userLinked_entry(void); handler_result_t pet_handler(EVENT_T event); void pet_entry(void); +handler_result_t dead_handler(EVENT_T event); +void dead_entry(void); + handler_result_t mainView_handler(EVENT_T event); +void mainView_entry(void); handler_result_t gameView_handler(EVENT_T event); +void gameView_entry(void); //Our definition of an hierachical state typedef struct hierarchical_state state_t; @@ -44,9 +50,10 @@ struct hierarchical_state { static bool firstStart = true; static bool registered = false; static bool userLinked = false; +static bool statsShowing = false; static const state_t Top_Level[2]; -static const state_t On_Level[3]; +static const state_t On_Level[4]; static const state_t Pet_Level[2]; static const state_t Top_Level[] = { @@ -92,13 +99,21 @@ static const state_t On_Level[] = { &Top_Level[0], // Parent state &Pet_Level[0], // Child state 2 // Hierarchical state level + }, + {//dead + dead_handler, // state handler + dead_entry, // Entry action handler + NULL, // Exit action handler + &Top_Level[0], // Parent state + NULL, // Child state + 2 // Hierarchical state level } }; static const state_t Pet_Level[] = { {//Main_View mainView_handler, // state handler - NULL, // Entry action handler + mainView_entry, // Entry action handler NULL, // Exit action handler &On_Level[2], // Parent state NULL, // Child state @@ -106,7 +121,7 @@ static const state_t Pet_Level[] = { }, {//Game_View TODO: not used yet gameView_handler, // state handler - NULL, // Entry action handler + gameView_entry, // Entry action handler NULL, // Exit action handler &On_Level[2], // Parent state NULL, // Child state @@ -181,6 +196,7 @@ handler_result_t on_handler(EVENT_T event) { } void on_entry(void) { + // displayHandler_handleEvent(REGISTERED); ioHandler_handleEvent(VIBRATE); ioHandler_handleEvent(SCREEN_ON); if (registered && userLinked) { @@ -222,10 +238,9 @@ void off_entry(void) { handler_result_t unregistered_handler(EVENT_T event) { printf("[FSM:unregistered_state_handler]: event: %d \n",event); switch (event) { - case REGISTER_CODE: DEBUG("[FSM:unregistered_state_handler]: REGISTER_CODE\n"); - displayHandler_handleEvent(REGISTERED); //is that right? + // displayHandler_handleEvent(REGISTERED); //is that right? displayHandler_handleEvent(REGISTER_CODE); return HANDLED; case REGISTERED: @@ -239,6 +254,7 @@ handler_result_t unregistered_handler(EVENT_T event) { } void unregistered_entry(void) { + DEBUG("[FSM:unregistered_state_handler]: Halooooo Lukas\n"); displayHandler_handleEvent(REGISTER_CODE); } @@ -256,11 +272,17 @@ handler_result_t userLinked_handler(EVENT_T event) { } void userLinked_entry(void) { + // displayHandler_handleEvent(READY); registered = true; } handler_result_t pet_handler(EVENT_T event) { switch (event) { + case DEAD: + DEBUG("[FSM:pet_handler]: DEAD\n"); + userLinked = false; + traverse_state(&On_Level[3]); //transition to dead + return HANDLED; default: DEBUG("[FSM:pet_handler]: UNHANDLED\n"); return UNHANDLED; @@ -268,11 +290,26 @@ handler_result_t pet_handler(EVENT_T event) { } void pet_entry(void) { - displayHandler_handleEvent(READY); //to draw the pet userLinked = true; traverse_state(&Pet_Level[0]); //transition to main_view } +handler_result_t dead_handler(EVENT_T event) { + switch (event) { + case BUTTON_OK_PRESSED: + DEBUG("[FSM:dead_handler]: BUTTON_OK_PRESSED\n"); + traverse_state(&On_Level[0]); //transition to register + return HANDLED; + default: + DEBUG("[FSM:dead_handler]: UNHANDLED\n"); + return UNHANDLED; + } +} + +void dead_entry(void) { + displayHandler_handleEvent(DEAD); +} + handler_result_t mainView_handler(EVENT_T event) { switch (event) { case BUTTON_OK_LONG: @@ -319,24 +356,40 @@ handler_result_t mainView_handler(EVENT_T event) { displayHandler_handleEvent(event); return HANDLED; case PET_FEED: - DEBUG("[FSM:mainView_handler]: PET_FEED\n"); - lwm2m_handleEvent(PET_FEED); + if (!statsShowing) { + DEBUG("[FSM:mainView_handler]: PET_FEED\n"); + lwm2m_handleEvent(PET_FEED); + } return HANDLED; case PET_PLAY: - DEBUG("[FSM:mainView_handler]: PET_PLAY\n"); - lwm2m_handleEvent(PET_PLAY); + if (!statsShowing) { + DEBUG("[FSM:mainView_handler]: PET_PLAY\n"); + traverse_state(&Pet_Level[1]); //transition to game_view + } return HANDLED; case PET_MEDICATE: - DEBUG("[FSM:mainView_handler]: PET_MEDICATE\n"); - lwm2m_handleEvent(PET_MEDICATE); + if (!statsShowing) { + DEBUG("[FSM:mainView_handler]: PET_MEDICATE\n"); + lwm2m_handleEvent(PET_MEDICATE); + } return HANDLED; case PET_CLEAN: - DEBUG("[FSM:mainView_handler]: PET_CLEAN\n"); - lwm2m_handleEvent(PET_CLEAN); + if (!statsShowing) { + DEBUG("[FSM:mainView_handler]: PET_CLEAN\n"); + lwm2m_handleEvent(PET_CLEAN); + } return HANDLED; case INFO_PRESSED: - DEBUG("[FSM:mainView_handler]: INFO_PRESSED\n"); - displayHandler_handleEvent(INFO_PRESSED); + if (!statsShowing) { + DEBUG("[FSM:mainView_handler]: show Statview\n"); + statsShowing = true; + displayHandler_handleEvent(INFO_PRESSED); + } + else { + DEBUG("[FSM:mainView_handler]: hide Statview\n"); + statsShowing = false; + displayHandler_handleEvent(READY); + } return HANDLED; default: DEBUG("[FSM:mainView_handler]: UNHANDLED\n"); @@ -344,11 +397,46 @@ handler_result_t mainView_handler(EVENT_T event) { } } +void mainView_entry(void) { + // displayHandler_handleEvent(READY); //to draw the pet +} + +static bool raus = false; + handler_result_t gameView_handler(EVENT_T event) { switch (event) { + case BUTTON_OK_PRESSED: + if (raus) { + traverse_state(&Pet_Level[0]); //transition to main_view + } + else { + raus = true; + } + return HANDLED; + case BUTTON_OK_RELEASED: + case BUTTON_UP_PRESSED: + case BUTTON_UP_RELEASED: + case BUTTON_DOWN_PRESSED: + case BUTTON_DOWN_RELEASED: + case BUTTON_LEFT_PRESSED: + case BUTTON_LEFT_RELEASED: + case BUTTON_RIGHT_PRESSED: + case BUTTON_RIGHT_RELEASED: + displayHandler_handleEvent(event); + return HANDLED; + case GAME_FINISHED: + DEBUG("[FSM:gameView_handler]: GAME_FINISHED\n"); + traverse_state(&Pet_Level[0]); //transition to main_view + lwm2m_handleEvent(PET_PLAY); + return HANDLED; default: DEBUG("[FSM:gameView_handler]: UNHANDLED\n"); return UNHANDLED; } } + +void gameView_entry(void) { + raus = false; + displayHandler_handleEvent(GAME_START); +} //EOF diff --git a/node/code/modules/fsm/include/events.h b/node/code/modules/fsm/include/events.h index 990e2db..5e86360 100644 --- a/node/code/modules/fsm/include/events.h +++ b/node/code/modules/fsm/include/events.h @@ -53,6 +53,7 @@ typedef enum { PET_ILL, PET_BORED, PET_DIRTY, + DEAD, VIBRATE, SCREEN_OFF, SCREEN_ON, @@ -69,7 +70,9 @@ typedef enum { XP, HUNGER, CLEANLINESS, - FUN + FUN, + GAME_START, + GAME_FINISHED, }EVENT_T; typedef struct{ diff --git a/node/code/modules/lwm2m_handler/lwm2m_handler.c b/node/code/modules/lwm2m_handler/lwm2m_handler.c index 960f9b8..201e762 100644 --- a/node/code/modules/lwm2m_handler/lwm2m_handler.c +++ b/node/code/modules/lwm2m_handler/lwm2m_handler.c @@ -43,7 +43,12 @@ static void lwm2m_write_callback(uint16_t event_id, callback_value value){ (void) value; switch (event_id) { case LWM2M_PET_NAME_ID: - trigger_event_string(NAME,value.str); + if (strcmp(value.str, "DEAD")){ + trigger_event(DEAD); + } + else { + trigger_event_string(NAME,value.str); + } break; case LWM2M_PET_COLOR_ID: trigger_event_int(COLOR,value.num);