# Logic Gates Simulator on Fruit Jam

## Overview

![Logic Gates Simulator running on the Adafruit Fruit Jam with a USB mouse and keyboard plugged in.](https://cdn-learn.adafruit.com/assets/assets/000/140/368/medium800/circuitpython_overview_hero.png?1760124932 )

The Logic Gates Simulator allows you to experiment and learn about all of the basic [Logic Gates](https://en.wikipedia.org/wiki/Logic_gate) in a fun and visual way. Interact with a virtual workspace displayed over DVI using a USB mouse and keyboard. Break free from virtual realm by integrating the physical buttons and NeoPixels on the Fruit Jam with the logic circuits in the simulation.

This project was inspired by old computer games like [Robot Odyssey](https://en.wikipedia.org/wiki/Robot_Odyssey), their modern counterparts like Factorio, and the book&nbsp;[Computer Engineering for Babies](https://hackylabs.com/products/computer-engineering-for-babies).

The project was demonstrated on an episode of Adafruit Show & Tell.

https://www.youtube.com/live/4-vCTnIWrNo?t=940s

## Parts
Featured
### Adafruit Fruit Jam - Mini RP2350 Computer

[Adafruit Fruit Jam - Mini RP2350 Computer](https://www.adafruit.com/product/6200)
We were catching up on a recent [hackaday hackchat with eben upton](https://hackaday.io/event/202122-raspberry-pi-hack-chat-with-eben-upton)&nbsp;and learned some fun facts: such as the DVI hack for the RP2040 was inspired by <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/6200)
[Related Guides to the Product](https://learn.adafruit.com/products/6200/guides)
![Angled shot of assembled mini computer PCB with plate.](https://cdn-shop.adafruit.com/640x480/6200-10.jpg)

Featured
### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)
![Angled Shot of the USB Wired Mouse - Two Buttons plus Wheel](https://cdn-shop.adafruit.com/640x480/2025-05.jpg)

Featured
### Mini Chiclet Keyboard - USB Wired - Black

[Mini Chiclet Keyboard - USB Wired - Black](https://www.adafruit.com/product/1736)
Add a good quality, slim keyboard to your&nbsp;Raspberry Pi, Beagle Bone Black, or other single-board-computer with this sleek black chiclet keyboard. It's a full QWERTY keyboard with a USB cable and is compatible with all operating systems. We tried many keyboards to find one that felt...

In Stock
[Buy Now](https://www.adafruit.com/product/1736)
[Related Guides to the Product](https://learn.adafruit.com/products/1736/guides)
![Angled shot of a Black woman's silver-blue manicured hands on a slim, black keyboard.](https://cdn-shop.adafruit.com/640x480/1736-04.jpg)

Featured
### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
![Official Raspberry Pi HDMI Cable - 1 meter](https://cdn-shop.adafruit.com/640x480/608-03.jpg)

Featured
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

Featured
### Snap-on Enclosure for Adafruit Fruit Jam

[Snap-on Enclosure for Adafruit Fruit Jam](https://www.adafruit.com/product/6425)
Here is a cool&nbsp;and minimal enclosure for your [Fruit Jam](https://www.adafruit.com/product/6200)&nbsp;to keep it safe during use and transport. This case has been custom-designed and 3D printed to accommodate all&nbsp;connection ports of the Fruit Jam. No screws or...

In Stock
[Buy Now](https://www.adafruit.com/product/6425)
[Related Guides to the Product](https://learn.adafruit.com/products/6425/guides)
![Angled Demo Shot of the Assembled Snap-on Enclosure with the Fruit Jam inside and powered on showing a rainbow effect of the LED's.](https://cdn-shop.adafruit.com/640x480/6425-02.jpg)

Featured
### 7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL

[7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL](https://www.adafruit.com/product/1667)
Yes, this is an adorable small HDMI television with incredibly high resolution **and built in 3W stereo speakers**! We tried to get the smallest possible HDMI/VGA display with high-res, high-contrast visibility. The visible display measures only 7" (17.8cm) diagonal, and the TFT comes...

In Stock
[Buy Now](https://www.adafruit.com/product/1667)
[Related Guides to the Product](https://learn.adafruit.com/products/1667/guides)
![Front view of assembled and powered on HDMI 4 Pi - 7" Display. The monitor displays a desktop background with a raspberry logo.](https://cdn-shop.adafruit.com/640x480/1667-00.jpg)

# Logic Gates Simulator on Fruit Jam

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Warning: Please use the latest release of 10.x or higher for the Fruit Jam. Also use the latest libraries for the best functionality.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_fruit_jam/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/101/655/medium640/install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg?1618943202)

![reset and boot highlighted](https://cdn-learn.adafruit.com/assets/assets/000/138/708/medium800/adafruit_products_Resetboot.jpg?1754331128 )

To enter the bootloader, hold down the **BOOT/**** BOOTSEL button**(highlighted in red above), and while continuing to hold it (don't let go!), press and release the**reset button**(highlighted in red or blue above).&nbsp;**Continue to hold the BOOT/BOOTSEL button until the RP2350 drive appears!**

If the drive does not appear, release all the buttons, and then repeat the process above.

You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **RP2350**.

&nbsp;

Drag the **adafruit-circuitpython-_boardname_-_language_-_version_.uf2** file to **RP2350.**

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png](https://cdn-learn.adafruit.com/assets/assets/000/132/253/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png?1726067809)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png](https://cdn-learn.adafruit.com/assets/assets/000/132/254/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png?1726067866)

The **RP2350** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png](https://cdn-learn.adafruit.com/assets/assets/000/132/255/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png?1726067932)

## Safe Mode

You want to edit your **code.py** or modify the files on your **CIRCUITPY** drive, but find that you can't. Perhaps your board has gotten into a state where **CIRCUITPY** is read-only. You may have turned off the **CIRCUITPY** drive altogether. Whatever the reason, safe mode can help.

Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode _bypasses any code in_ **boot.py** (where you can set **CIRCUITPY** read-only or turn it off completely). Second, _it does not run the code in_ **code.py**. And finally, _it does not automatically soft-reload when data is written to the_ **CIRCUITPY** _drive_.

Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the **CIRCUITPY** drive.

### Entering Safe Mode
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)

### In Safe Mode

If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.

If you connect to the serial console, you'll find the following message.

```terminal
Auto-reload is off.
Running in safe mode! Not running saved code.

CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.
```

You can now edit the contents of the **CIRCUITPY** drive. Remember, _your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode._

## Flash Resetting UF2

If your board ever gets into a really _weird_ state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RP2350. which will do a 'deep clean' on your Flash Memory. **You will lose all the files on the board** , but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.

[Download flash erasing "nuke" UF2 for RP2350](https://cdn-learn.adafruit.com/assets/assets/000/132/526/original/rp2350_flash_nuke.uf2)
# Logic Gates Simulator on Fruit Jam

## Code

## Getting the Program's Files

To use the application, you need to obtain **code.py** with the game program to place on the Fruit Jam **CIRCUITPY** drive.

Thankfully, this can be done in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file.

Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named **CIRCUITPY**.

Extract the contents of the zip file, copy the **lib** directory files to **CIRCUITPY/lib**. Copy the **logic\_gates\_assets** directory to **CIRCUITPY/**** logic\_gates\_assets **directory. Copy the files** code.py **,** entity.py **, and** workspace.py **to your** CIRCUITPY** drive. The program should self start.

## Drive Structure

After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum.

![Fruit Jam Logic Gates Simulator required project files and libraries screenshot](https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/folder-images/Fruit_Jam_Fruit_Jam_Logic_Gates.png?raw=true )

## Code

The **code.py** for the Logic Gates Simulator app is shown below.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Fruit_Jam/Fruit_Jam_Logic_Gates/code.py

# Logic Gates Simulator on Fruit Jam

## Usage

Using the basic functionality of the Logic Gates Simulator only requires a USB mouse, but the functionality and ease of use is expanded if you also have a USB keyboard connected.

## Add Parts

To add a new part to the workspace first click the 'add' button in the top left corner. Once the toolbox grid is shown click the part to add. Finally, click on the workspace in the location where the part should get put.

![Screen recording of a logic gate being added to the workspace by clicking on the add button in the top left, then clicking the desired gate, and finally clicking on the workspace in the desired location.](https://cdn-learn.adafruit.com/assets/assets/000/140/324/medium640thumb/circuitpython_add_part.jpg?1760112537)

![Toolbox menu showing all of the available parts that can be placed on the workspace](https://cdn-learn.adafruit.com/assets/assets/000/140/848/medium640/circuitpython_updated_toolbox_parts.png?1761925912)

The available parts are:

- And Gate - Outputs logic signal 1 when both inputs are logic signal 1, otherwise outputs 0.
- Nand Gate - Outputs logic signal 1 when at least one input signal is 0, otherwise outputs 0.
- Or Gate - Outputs logic signal 1 when at least one input signal is 1, otherwise outputs 0.
- Nor Gate - Outputs logic signal 1 when both input signals are 0, otherwise outputs 0.
- Not Gate - Outputs logic signal 1 when the input signal is 0 and outputs logic signal 0 when input signal is 1.
- Xor Gate - Outputs logic signal 1 when one input signal is 1 and the other input signal is 0, otherwise outputs 0.
- Xnor Gate - Outputs logic signal 1 when both input signals are 1 or both input signals are 0, otherwise outputs 0.
- Virtual Push Button - A circle push button that can be clicked with the mouse to toggle the logic signal that it outputs between 1 and 0.
- Output Panel - A basic rectangle visual output that shows a 1 or 0 based on the logic signal that is input to it.
- NeoPixel Output - Accepts 3 logic signal inputs that correspond to red, green, and blue. The NeoPixels on the Fruit Jam are updated to reflect the color matching the value of logic signals being input.
- Physical Button - A circle button that is hooked up to one of the hardware buttons on the Fruit Jam. Pressing the matching physical button will set the logic signal output to 1 and releasing the button will return the signal to 0.
- Wire - A straight or 90 degree turn line that connects two entities together. Logic signal flows through the wire getting passed from outputs of one entity to inputs of another.
- Signal Transmitter - Accepts a logic signal in and transmits the signal to all paired receivers. It's possible to make up to 5 transmitters at once. Transmitters are assigned a letter A-E.
- Signal Receiver - Receives signal value from the paired transmitter. Multiple receivers can be paired to the same transmitter. It will be paired to the transmitter matching it's letter.

## Move Parts

To move a part that is already on the workspace, right click on it to pick it up attaching it to the mouse cursor. Then move the mouse to the desired location and left click to put the part down at the location of the cursor.

![Screen recording of moving a part on the workspace](https://cdn-learn.adafruit.com/assets/assets/000/140/325/medium640thumb/circuitpython_move_part.jpg?1760112731)

## Delete Parts

Deleting parts is similar to moving them. Start by right clicking on a part that is on the workspace to pick it up. Then move the mouse up to the add button in the top left and left click on it. When a part is attached to the cursor clicking the add button will remove the part from the cursor thus deleting it from existence.

![Screen recording of a part being deleted from the workspace](https://cdn-learn.adafruit.com/assets/assets/000/140/326/medium640thumb/circuitpython_delete_part.jpg?1760112806)

### Toggle Part States

`Wires`, logic gates, `SignalTransmitter`, `SignalReceiver`, and the&nbsp;`NeoPixelOutput` can be left clicked to toggle or cycle through possible states. For logic gates and the `NeoPixelOutput` left clicking them will toggle between the inputs being to the left of the gate or being above and below the gate.&nbsp;

For `Wires`, they'll cycle between the possible straight and 90 degree connections that are supported by the simulator.

For signal transmitter and receivers clicking cycles between the available pairing letters A-E.

![Screen recording of a logic gate and wire being left clicked to cycle between the different available states](https://cdn-learn.adafruit.com/assets/assets/000/140/330/medium640thumb/circuitpython_cycle_part_states.jpg?1760116483)

With a USB mouse and the above actions you can do all of the basics with the simulator: laying out logic gates, buttons, output panels, and NeoPixelOutputs. Hooking up buttons to the logic gate inputs will allow you to experiment with the different logical rules that govern each gate. Use the NeoPixelOutput if you want to see that glowing rainbow goodness instead of cold logical ones and zeros.

## Advanced Usage

Connecting a USB keyboard to the Fruit Jam it will unlock some more advanced capabilities of the simulator. The two biggest features unlocked are the ability to scroll the workspace and saving/opening the workspace into any of 10 available storage slots. All features supported by the keyboard allow the definition of custom Hotkeys.

### Custom Hotkeys

&nbsp;There is a dictionary mapping for hotkeys that makes it easy to customize the hotkeys instead of sticking with the defaults. The default hotkeys dictionary is shown below. The dictionary maps byte-strings of keyboard keypress data to strings that represent the possible actions.

```auto
HOTKEYS = {
    b"\x1b[A": "scroll_up",  # up arrow
    b"\x1b[B": "scroll_down",  # down arrow
    b"\x1b[C": "scroll_right",  # right arrow
    b"\x1b[D": "scroll_left",  # left arrow
    b"q": "eyedropper",
    b"s": "save",
    b"o": "open",
    b"a": "add",
    b"i": "import",
    b"\x08": "remove",  # backspace
    b"\x1b[3~": "remove",  # delete
}
```

To customize the hotkeys, copy this dictionary into **code.py** , replace the byte-string keys with whatever keyboard press events you want to use for each action then add it as the value for keyword argument&nbsp;`hotkeys` to the `Workspace` constructor.

```auto
workspace = Workspace(neopixels, (btn_1, btn_2, btn_3), hotkeys=HOTKEYS)
```

### Scrolling

Scrolling uses the arrow keys by default, and is very straight forward. Press the arrow key matching the direction you want to scroll and the workspace will get shifted revealing more space in the specified direction.&nbsp;

![Screen recording of the workspace being scrolled with the arrow keys revealing more parts that have been placed.](https://cdn-learn.adafruit.com/assets/assets/000/140/328/medium640thumb/circuitpython_scroll_workspace.jpg?1760115626)

### Save, Import and Open Workspace

The save and open feature makes use of the **CPSAVES** partition of flash storage to save JSON files that represent the state of the workspace and all entities on it.&nbsp;

To save the current workspace, press the **'s'** key on the keyboard. A prompt will appear asking for a slot number save to. Enter any number 0-9. The current workspace will get serialized to JSON and saved in a file associated with the selected slot number.

To open from a saved slot, press the **'o'** key on the keyboard. A prompt will appear asking for a slot number to open from. Enter any number 0-9. It will attempt to load the the file for the given slot number and populate the workspace based on the data contained within it. If there was no save file in that slot it will output a message indicating so.

It's possible to copy the save files out of **CPSAVES** and send them to your friends. To import a save file save it in **CIRCUITPY** with the exact filename **logic\_gates\_import.json**. Press the **'i'** on the keyboard. A prompt will appear asking for a slot number to import the file into. Enter any number 0-9. It will copy the contents of **logic\_gates\_import.json** into the specified save slot.

![Screen recording of workspace being saved into slot 8, and then opening save slot 2 and loading the workspace from it.](https://cdn-learn.adafruit.com/assets/assets/000/140/329/medium800thumb/circuitpython_save_and_open.jpg?1760116113 Saving and opening storage slots)

### Convenience Actions

The remaining hotkeys don't do anything functionally new, instead they make existing actions a little more quick and convenient.

- Add - Pressing the **'a'** key will open the toolbox grid, the same as if the add button in the top left corner were clicked.
- Remove - Pressing **'del'** or **'backspace'** when there is an entity attached to the mouse will remove that entity from the mouse thus deleting it from the existence.&nbsp;
- Eyedropper/Pipette - Pressing the **'q'** key will activate the eyedropper or pipette action. This is similar to the tool by the same name in photo editing applications. It allows you to quickly duplicate existing parts that are on the workspace. To use it, move your mouse to the part that you want to duplicate and press **'q'** , a copy of the entity will appear and be attached to the mouse ready for you to move it and place it on the workspace. If there is already an entity attached to the mouse then pressing **'q'** will remove the attached entity, the same as if **'del'** or **'backspace'** were pressed. This action and it's default key **'q'** are an homage to the video game Factorio which has the same action on this hotkey by default, and was part of the inspiration for this simulator.

![Screen recording of a virtual push button being duplicated with the eyedropper action.](https://cdn-learn.adafruit.com/assets/assets/000/140/327/medium800thumb/circuitpython_duplicate_part.jpg?1760115085 Duplicating a part with the eyedropper action)

# Logic Gates Simulator on Fruit Jam

## Code Explanation

The code for the project is broken into 3 files, from highest level to lowest they are **code.py** , **workspace.py** and **entity.py**.

## **code.py**

This file is responsible for initializing the hardware peripherals and setting up the display group and `Workspace` object. The main loop first checks for mouse and keyboard input, clicks and keypresses get passed into the `Workspace` object to be dealt with, mouse movement gets handled here in **code.py**. Next the code reads the current values of the hardware buttons on the Fruit Jam and if any button values have changed it calls `workspace.update()` to run the logic simulation with the new values from the buttons.

The **code.py** file is embedded below, it contains comments describing the purpose of each part of the code.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Fruit_Jam/Fruit_Jam_Logic_Gates/code.py

## **workspace.py**

The **workspace.py** file contains two classes `Workspace` and `ToolBox`. These objects handle most of the user interface and interactions when the user presses a key or clicks the mouse.&nbsp;

### `Workspace`

This class provides a scroll-able area that logic gates and other&nbsp;`Entity` objects can be placed onto. At its core, visually, is a `TileGrid` that is made larger than the display resolution and moved around when the user scrolls. The `add_entity()` and `remove_entity()` take care of everything needed for placing or removing entities. User interactions are handled inside of `handle_key_press()` and `handle_mouse_click()`. For key presses, there is a dictionary defined for hotkeys that can be customized to change which key on the keyboard does any specific action, see the [Usage](https://learn.adafruit.com/logic-gates-simulator-on-fruit-jam/usage) page for details on custom hotkeys.

Saving and loading from any of 10 different slots is handled by the functions: `json()`, `create_entity_from_json()`, `load_from_json()`. The user is prompted to select a slot by entering a number 0-9, their input is read with the `read_input()` function. A multi-purpose `Label` object is used for both outputting messages to the user, and displaying the input that they type.

The `update()` function will run one the logic simulation, updating everything visually on the display and NeoPixels as needed based on the logic values and connections. The bulk of the functionality is defined within the `Entity` classes detailed below, `workspace.update()` calls the update and value functions on all existing `Entity` objects.

`entity_at()` is the last notable function. It accepts a location in `x, y` tile coordinates and returns the&nbsp;`Entity` object that is at the specified location if there is one, otherwise it returns `None`.

There is an add button with a plus icon in the top left corner, when clicked it shows the `ToolBox` on top of the Workspace for the user to select a new part from.

### `ToolBox`

The `ToolBox` responsible for showing a grid of available parts that the user can select from when they want to add something new to the workspace. A `ToolBox` instance is created and held inside of the `Workspace` object. It uses a `GridLayout` object with each cell containing a `TextBox` and icon `TileGrid`.

The `ToolBox` grid is created dynamically from a list of objects that represent each type of logic gate and other `Entity` that are available. Each object contains the necessary information to show the proper icon for the part and a reference to the constructor function that will create an instance of the `Entity` for the part.&nbsp;

`ToolBox` has its own&nbsp;`handle_mouse_click()` which gets called by the `Workspace` whenever the mouse is clicked while the `ToolBox` is showing. If the user clicks on a part, then an instance of that parts `Entity` class is created and attached to the mouse, ready to place it at the desired location. If the user clicked on empty space, the `ToolBox` is closed, revealing the `Workspace` underneath.

&nbsp;

![ToolBox interface showing a grid of the available parts that can be placed on the Workspace.](https://cdn-learn.adafruit.com/assets/assets/000/140/849/medium800/circuitpython_updated_toolbox_parts.png?1761926538 )

The code for **workspace.py** included both `Workspace` and `ToolBox` classes is embedded below. There are comments describing the purpose of each part of the code.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Fruit_Jam/Fruit_Jam_Logic_Gates/workspace.py

### **entity.py**

This files contains the lowest level functionality of all of the logic gates and other types of parts. There is a base class `Entity` that contains shared functionality which all of the other objects extend. There is a `TwoInputOneOutputGate` class that extends `Entity` and implements all of the functionality and state management for all logic gates that have two inputs and one output, which is all gates except the NOT gate.

The gates will check in their input entity locations to find the `Entity` or `Wire` that is connected to the inputs and get its value. Once the input values are known it applies the gate-specific logic rules to determine what signal should get output. The relevant `Entity` objects all have a `value` property that is used to access their current logic signal output.

The entity types that are left-clickable to cycle through possible states have a `handle_click()` function that gets called by `Workspace`. Inside they update the sprite tiles and input entity locations as appropriate for the new state.

### Color Mapping with TilePaletteMapper

All Entity objects make use of the core module [TilePaletteMapper](https://docs.circuitpython.org/en/latest/shared-bindings/tilepalettemapper/index.html#tilepalettemapper.TilePaletteMapper) to set the wire colors to green when the logic signal is 1 and black when the logic signal is 0. This is a fundamental building block that the graphics of the Logic Gates Simulator are based on. I've included a small example and illustration to show how it works. This basic script demonstrates how it's used.

```auto
from displayio import OnDiskBitmap, TileGrid, Group
import supervisor
from tilepalettemapper import TilePaletteMapper

main_group = Group()
display = supervisor.runtime.display
display.root_group = main_group

spritesheet_bmp = OnDiskBitmap("logic_gates_assets/sprites.bmp")

tpm = TilePaletteMapper(
    spritesheet_bmp.pixel_shader,  # input Palette
    len(spritesheet_bmp.pixel_shader),  # input color count
)

tilegrid = TileGrid(
    bitmap=spritesheet_bmp,
    pixel_shader=tpm,
    default_tile=8,
    width=10, height=10,
    tile_width=24, tile_height=24
)

main_group.append(tilegrid)

# left gate and wire tiles
tilegrid[1, 1] = 0
tilegrid[1, 2] = 4
tilegrid[2, 2] = 5
tilegrid[1, 3] = 20

# right gate and wire tiles
tilegrid[4, 1] = 0
tilegrid[4, 2] = 4
tilegrid[5, 2] = 5
tilegrid[4, 3] = 20

# use TilePaletteMapper to map wire colors
# from spritesheet to green or black
color_index_mapping = list(range(len(spritesheet_bmp.pixel_shader)))

# change dark red top input wire to green
color_index_mapping[3] = 7

# change dark green bottom input wire to black
color_index_mapping[4] = 1

# change dark blue output wire to green
color_index_mapping[5] = 7

print(color_index_mapping)
# apply changed color mapping to all tiles used by the right gate and wires
tpm[4, 1] = color_index_mapping
tpm[4, 2] = color_index_mapping
tpm[5, 2] = color_index_mapping
tpm[4, 3] = color_index_mapping

while True:
    pass
```

This script uses a `TileGrid` with the project's spritesheet bitmap to draw two XOR gates. The left gate is has the default colors that appear in the spritesheet. The right gate has one of its input wires and the output wire mapped to a bright green color, and its other input mapped to black.

`TilePaletteMapper` allows setting a different color mapping for every tile within a TileGrid. For Palette based mappings, it can substitute a different color index for any existing index in the input palette. This code maps index `7` in place of indexes `3` and `5` the input and output wire colors respectively. It also maps index `1` in place of index `4` to set the bottom input wire color to black.

The screenshot of the palette shows the default color mapping that is embedded within the spritesheet, these colors and indexes are what the `TilePaletteMapper` manipulates for each tile in the grid.

![](https://cdn-learn.adafruit.com/assets/assets/000/140/321/medium640/circuitpython_tpm_demo_screenshot.png?1760109974)

![Color palette showing the 8 colors used by the TilePaletteMapper. Notable colors and indexs are index 1: Black, index 3: dark red, index 4: dark green, index 5: dark blue, and index 7: bright green.](https://cdn-learn.adafruit.com/assets/assets/000/140/322/medium640/circuitpython_palette2.png?1760110375)

The following classes are Entities that aren't logic gates:

- `OutputPanel` - A basic rectangle visual output that shows a 1 or 0 based on the logic signal that is input to it.
- `VirtualPushButton` - A circle push button that can be clicked with the mouse to toggle the logic signal that it outputs between 1 and 0.
- `PhysicalButton` - A circle button that is hooked up to one of the hardware buttons on the Fruit Jam. Pressing the matching physical button will set the logic signal output to 1 and releasing the button will return the signal to 0.
- `Wire` - A straight or 90 degree turn line that connects two entities together. Logic signal flows through the wire getting passed from outputs of one entity to inputs of another.
- `NeoPixelOutput` - Accepts 3 logic signal inputs that correspond to red, green, and blue. The NeoPixels on the Fruit Jam are updated to reflect the color matching the value of logic signals being input.
- `SignalTransmitter` - Accepts a logic signal input and transmits it to all paired receivers.
- `SignalReceiver` - Receives signal from the paired transmitter and outputs it to be connected to wires and other entities.

The following classes are all of the logic gates supported by the simulator.

- `AndGate` - Outputs logic signal 1 when both inputs are logic signal 1, otherwise outputs 0.
- `NandGate` - Outputs logic signal 1 when at least one input signal is 0, otherwise outputs 0.
- `OrGate` - Outputs logic signal 1 when at least one input signal is 1, otherwise outputs 0.
- `NorGate` - Outputs logic signal 1 when both input signals are 0, otherwise outputs 0.
- `XorGate` - Outputs logic signal 1 when one input signal is 1 and the other input signal is 0, otherwise outputs 0.
- `XnorGate` - Outputs logic signal 1 when both input signals are 1 or both input signals are 0, otherwise outputs 0.
- `NotGate` - Outputs logic signal 1 when input signal is 0 and outputs logic signal 0 when input signal is 1.

The **entity.py** code file is embedded below. It contains comments detailing what each part of the code does.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Fruit_Jam/Fruit_Jam_Logic_Gates/entity.py


## Guide Products

### Adafruit Fruit Jam - Mini RP2350 Computer

[Adafruit Fruit Jam - Mini RP2350 Computer](https://www.adafruit.com/product/6200)
We were catching up on a recent [hackaday hackchat with eben upton](https://hackaday.io/event/202122-raspberry-pi-hack-chat-with-eben-upton)&nbsp;and learned some fun facts: such as the DVI hack for the RP2040 was inspired by <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/6200)
[Related Guides to the Product](https://learn.adafruit.com/products/6200/guides)
### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)
### Mini Chiclet Keyboard - USB Wired - Black

[Mini Chiclet Keyboard - USB Wired - Black](https://www.adafruit.com/product/1736)
Add a good quality, slim keyboard to your&nbsp;Raspberry Pi, Beagle Bone Black, or other single-board-computer with this sleek black chiclet keyboard. It's a full QWERTY keyboard with a USB cable and is compatible with all operating systems. We tried many keyboards to find one that felt...

In Stock
[Buy Now](https://www.adafruit.com/product/1736)
[Related Guides to the Product](https://learn.adafruit.com/products/1736/guides)
### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
### Snap-on Enclosure for Adafruit Fruit Jam

[Snap-on Enclosure for Adafruit Fruit Jam](https://www.adafruit.com/product/6425)
Here is a cool&nbsp;and minimal enclosure for your [Fruit Jam](https://www.adafruit.com/product/6200)&nbsp;to keep it safe during use and transport. This case has been custom-designed and 3D printed to accommodate all&nbsp;connection ports of the Fruit Jam. No screws or...

In Stock
[Buy Now](https://www.adafruit.com/product/6425)
[Related Guides to the Product](https://learn.adafruit.com/products/6425/guides)
### 7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL

[7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL](https://www.adafruit.com/product/1667)
Yes, this is an adorable small HDMI television with incredibly high resolution **and built in 3W stereo speakers**! We tried to get the smallest possible HDMI/VGA display with high-res, high-contrast visibility. The visible display measures only 7" (17.8cm) diagonal, and the TFT comes...

In Stock
[Buy Now](https://www.adafruit.com/product/1667)
[Related Guides to the Product](https://learn.adafruit.com/products/1667/guides)

## Related Guides

- [Using a Mouse with USB Host](https://learn.adafruit.com/using-a-mouse-with-usb-host.md)
- [Using a Keyboard with USB Host](https://learn.adafruit.com/using-a-keyboard-with-usb-host.md)
- [Adafruit Fruit Jam](https://learn.adafruit.com/adafruit-fruit-jam.md)
- [No-Code IoT Pool Monitor](https://learn.adafruit.com/iot-pool.md)
- [USB Host to BLE Keyboard Adapter](https://learn.adafruit.com/esp32-s3-usb-to-ble-keyboard-adapter.md)
- [Breakout Game on the Metro RP2350 and Fruit Jam](https://learn.adafruit.com/breakout-game-on-metro-rp2350-and-fruit-jam.md)
- [No-Code, No-Solder Monitoring For Perfect Bread](https://learn.adafruit.com/no-code-no-solder-temperature-monitoring-with-wippersnapper-offline.md)
- [Color Sensing Music Player](https://learn.adafruit.com/color-sensing-music-player.md)
- [Mac Classic Fruit Jam](https://learn.adafruit.com/mac-classic-fruit-jam.md)
- [Wireless Control Button for WLED Projects](https://learn.adafruit.com/wireless-control-button-for-wled-projects.md)
- [Digital Inputs with Adafruit IO WipperSnapper](https://learn.adafruit.com/digital-inputs-with-adafruit-io-wippersnapper.md)
- [Using a Raspberry Pi as a Router](https://learn.adafruit.com/using-a-raspberry-pi-as-a-router.md)
- [MEMENTO Focus Stacking](https://learn.adafruit.com/memento-focus-stacking.md)
- [Integrating Color Sensors with itsaSNAP and HomeKit](https://learn.adafruit.com/integrating-color-sensors-with-itsasnap-and-homekit.md)
- [LED Matrix FIFA World Cup Scoreboard](https://learn.adafruit.com/led-matrix-fifa-world-cup-scoreboard.md)
- [NeXT Bus Mouse to USB HID with CircuitPython](https://learn.adafruit.com/next-bus-mouse-to-usb-hid-with-circuitpython.md)
- [Bendable Sound Reactive Lamp with WLED](https://learn.adafruit.com/bendable-sound-reactive-lamp-with-wled.md)
