RANPW
A versatile platform inspired by Tamagotchi, featuring games and productivity apps, powered by the mbed NXP LPC1768.
Project Overview
The central concept behind the RANPW project is to create a dynamic, Tamagotchi-inspired tool enriched with a selection of games (LCatch, Pong, and LockY) and productivity applications (Cronometer and Termometer). This versatile platform encourages high modularity, enabling individuals with basic C++ knowledge to seamlessly develop and incorporate their custom apps and games. RANPW is designed to operate on the mbed NXP LPC1768 microcontroller, coupled with the mbed application board.
Used Hardware and Library
LCD: C12832
The 32x128 pixel LCD display serves as the primary visual interface for all interactions within the application. To achieve seamless control over the display, I’ve customized the C12832.h library to ensure compatibility with the project’s broader software ecosystem.
Joystick
The joystick plays a pivotal role in navigating through all application interfaces. Its management is facilitated through the APIs provided directly by “mbed.h,” which can be accessed here.
Potentiometer
Both potentiometers are integral to specific user interactions, with one notably enhancing gameplay in the LockY game. The control of these potentiometers is streamlined through the APIs provided by “mbed.h,” as detailed here.
Temperature sensor: LM75BD
The LM75BD temperature sensor is utilized in the “Termometer” application to capture environmental temperature data. The sensor is integrated into the project using the LM75B.h library, with minor modifications to ensure compatibility with the Embed OS CE platform.
Accelerometer: MMA7660
The MMA7660 accelerometer contributes significantly to user interactions, particularly in the Hell and Pong games. To collect data from this component, the MMA7660.h library has been employed with slight modifications to align it with the project’s requirements.
Software
Thread Overview
At startup, RANPW initializes three distinct threads to manage various aspects of its functionality:
Thread 1: User Interface and Interaction
This thread is responsible for overseeing the entire user interface and facilitating interaction with end-users. It dynamically creates and initializes instances of all apps and games while orchestrating their display on the LCD screen. Further insights into this thread’s workings can be found in the Ranpw.h and Ranpw.cpp files.
Thread 2: Kraken’s Management
Thread 2 operates on a straightforward principle, employing basic rand()
functions to introduce wait times of 1 to 5 minutes. During these intervals, it randomly decreases the pet’s hunger by a value ranging from 1 to 5. Should the hunger level plummet to zero, the pet’s life diminishes at varying rates—1, 2, or 3 points per minute. Conversely, if hunger surpasses 20, the pet gains 1 life point. Notably, both life and hunger levels have a cap of 25. Detailed insights into this thread’s functionality are available in the live()
function within Kraken.cpp.
Thread 3: Data Saving Management
Thread 3 operates with a clear focus on data integrity. It consistently monitors the data stored in the members of the ConcurrentData structure. This structure is vital for ensuring safe data access across multiple threads. When disparities between the stored data and in-memory data are detected, Thread 3 takes action, overwriting the data and saving the respective file in the device’s internal memory.
Class Overview
In the process of realizing the RANPW project, I’ve meticulously crafted 15 different classes to lay the foundation for its functionality and modularity. Each of these components plays a specific role in the project’s architecture:
ConcurrentData
This essential structure serves as the backbone for managing concurrent data access across multiple threads. It ensures data integrity and consistency, preventing conflicts and race conditions.
DataSaver
The DataSaver class is responsible for handling data saving and data loading operations, ensuring that changes to critical data are persistently stored in the device’s internal memory.
Ranpw
The Ranpw class serves as the central hub for user interface management. It oversees the creation and initialization of app and game instances, orchestrates their display on the LCD screen, and manages user input via various hardware interfaces.
Kraken
The Kraken class embodies the behavior and lifecycle of the virtual pet, monitoring key metrics such as hunger and life. It simulates the pet’s interactions with the user.
Bag
The Bag class manages the virtual inventory system, allowing users to collect and interact with food items within the application. It enhances gameplay and engagement.
Cronometer
The Cronometer is a specialized application designed to provide users with a versatile stopwatch.
LCatch
LCatch is one of the interactive games featured in RANPW. It provides an engaging experience where users can test their reflexes and coordination. What sets LCatch apart is its incremental speed feature, where the game progressively increases in difficulty as players successfully capture objects.
LockY
LockY is another game that offers users a unique challenge. It leverages hardware components like potentiometers for gameplay.
Pong
In Pong, players use the accelerometer as a unique input method to control the paddle and engage in the timeless challenge of bouncing a ball.
Hell
Unlike other games, Hell only surfaces when the Kraken’s life reaches zero, triggering the Kraken’s respawn process. Distinguished by its lack of a tutorial, Hell immerses players in a realm where they need to discover how to play by themselves.
Termometer
This class allows users to monitor temperature levels in their environment. What sets this component apart is its ability to visualize temperature data through a graph.
Optimization Strategy
Given the scope of this project, ensuring optimal resource utilization became a crucial aspect of development. To achieve this, I delved into various optimization techniques to maximize the efficiency of the system. Several key strategies were implemented:
-
Global Initialization: To minimize memory usage, I opted to initialize certain variables and resources globally in the main function. This approach prevented them from being allocated in the .bss section and instead placed them in the stack, reducing the overall memory footprint.
-
Sensor Initialization: I centralize sensor initialization within a dedicated class, initializing sensors only once and passing their pointers where needed throughout the project. This approach eliminates redundant sensor reinitialization, conserving more memory
-
Scoped Game Initialization: To further optimize memory allocation, I strategically limited the scope of game initialization. Games are initialized only when required, ensuring they occupy memory space only when actively in use.
-
Pointer Management: Ensuring the absence of dangling or unclean pointers was paramount.
How to Install
Binary
All that is necessary is to download the binary available here and then insert it into the internal storage of the microcontroller.
Compile Yourself
To compile it yourself, I recommend following the official embed OS CE wiki instead. In particular, once the development environment has been configured, you can choose to compile it:
- On the command line
- Using the CLion IDE
- Using the VS Code IDE
Remember that if you add something new to the project you need also to add it to the CMakeList.txt file.