diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java
index 710094ecd..d7f5edf80 100644
--- a/src/main/java/dan200/computercraft/ComputerCraft.java
+++ b/src/main/java/dan200/computercraft/ComputerCraft.java
@@ -14,6 +14,7 @@ import dan200.computercraft.api.media.IMediaProvider;
 import dan200.computercraft.api.peripheral.IPeripheral;
 import dan200.computercraft.api.peripheral.IPeripheralProvider;
 import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
 import dan200.computercraft.api.turtle.ITurtleUpgrade;
 import dan200.computercraft.core.filesystem.ComboMount;
@@ -38,15 +39,13 @@ import dan200.computercraft.shared.peripheral.modem.BlockAdvancedModem;
 import dan200.computercraft.shared.peripheral.modem.WirelessNetwork;
 import dan200.computercraft.shared.peripheral.printer.TilePrinter;
 import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
+import dan200.computercraft.shared.pocket.peripherals.PocketModem;
 import dan200.computercraft.shared.proxy.ICCTurtleProxy;
 import dan200.computercraft.shared.proxy.IComputerCraftProxy;
 import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
 import dan200.computercraft.shared.turtle.blocks.TileTurtle;
 import dan200.computercraft.shared.turtle.upgrades.*;
-import dan200.computercraft.shared.util.CreativeTabMain;
-import dan200.computercraft.shared.util.IDAssigner;
-import dan200.computercraft.shared.util.IEntityDropConsumer;
-import dan200.computercraft.shared.util.WorldUtil;
+import dan200.computercraft.shared.util.*;
 import io.netty.buffer.Unpooled;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.player.EntityPlayer;
@@ -75,9 +74,7 @@ import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 
 ///////////////
 // UNIVERSAL //
@@ -163,6 +160,12 @@ public class ComputerCraft
         public static TurtleModem advancedModem;
     }
 
+    public static class PocketUpgrades
+    {
+        public static PocketModem wirelessModem;
+        public static PocketModem advancedModem;
+    }
+
     public static class Config {
         public static Configuration config;
 
@@ -186,7 +189,6 @@ public class ComputerCraft
         public static Property computerSpaceLimit;
         public static Property floppySpaceLimit;
         public static Property maximumFilesOpen;
-
     }
 
     // Registries
@@ -204,6 +206,7 @@ public class ComputerCraft
     private static List<IBundledRedstoneProvider> bundledRedstoneProviders = new ArrayList<IBundledRedstoneProvider>();
     private static List<IMediaProvider> mediaProviders = new ArrayList<IMediaProvider>();
     private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<ITurtlePermissionProvider>();
+    private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<String, IPocketUpgrade>();
 
     // Implementation
     @Mod.Instance( value = "ComputerCraft" )
@@ -539,6 +542,18 @@ public class ComputerCraft
         return true;
     }
 
+    public static void registerPocketUpgrade( IPocketUpgrade upgrade )
+    {
+        String id = upgrade.getUpgradeID().toString();
+        IPocketUpgrade existing = pocketUpgrades.get( id );
+        if( existing != null )
+        {
+            throw new RuntimeException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " pocket computer'. UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " pocket computer'" );
+        }
+
+        pocketUpgrades.put( id, upgrade );
+    }
+
     public static void registerPeripheralProvider( IPeripheralProvider provider )
     {
         if( provider != null && !peripheralProviders.contains( provider ) )
@@ -659,6 +674,37 @@ public class ComputerCraft
         return null;
     }
 
+    public static IPocketUpgrade getPocketUpgrade(String id) {
+        return pocketUpgrades.get( id );
+    }
+
+    public static IPocketUpgrade getPocketUpgrade( ItemStack stack )
+    {
+        if( stack == null ) return null;
+
+        for (IPocketUpgrade upgrade : pocketUpgrades.values())
+        {
+            ItemStack craftingStack = upgrade.getCraftingItem();
+            if( craftingStack != null && InventoryUtil.areItemsStackable( stack, craftingStack ) )
+            {
+                return upgrade;
+            }
+        }
+
+        return null;
+    }
+
+    public static Iterable<IPocketUpgrade> getVanillaPocketUpgrades() {
+        List<IPocketUpgrade> upgrades = new ArrayList<IPocketUpgrade>();
+        for(IPocketUpgrade upgrade : pocketUpgrades.values()) {
+            if(upgrade instanceof PocketModem) {
+                upgrades.add( upgrade );
+            }
+        }
+
+        return upgrades;
+    }
+
     public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
     {
         return IDAssigner.getNextIDFromDirectory(new File(getWorldDir(world), parentSubPath));
diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
index c88bde40e..c4194f5b2 100644
--- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
+++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
@@ -14,6 +14,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
 import dan200.computercraft.api.peripheral.IPeripheral;
 import dan200.computercraft.api.peripheral.IPeripheralProvider;
 import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
 import dan200.computercraft.api.turtle.ITurtleUpgrade;
 import net.minecraft.util.EnumFacing;
@@ -270,6 +271,17 @@ public final class ComputerCraftAPI
         }
     }
 
+    public static void registerPocketUpgrade(IPocketUpgrade upgrade) {
+        findCC();
+        if(computerCraft_registerPocketUpgrade != null) {
+            try {
+                computerCraft_registerPocketUpgrade.invoke( null, upgrade );
+            } catch (Exception e) {
+                // It failed
+            }
+        }
+    }
+
     // The functions below here are private, and are used to interface with the non-API ComputerCraft classes.
     // Reflection is used here so you can develop your mod without decompiling ComputerCraft and including
     // it in your solution, and so your mod won't crash if ComputerCraft is installed.
@@ -308,6 +320,9 @@ public final class ComputerCraftAPI
                 computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class[] {
                     ITurtlePermissionProvider.class
                 } );
+                computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class[] {
+                    IPocketUpgrade.class
+                } );
             } catch( Exception e ) {
                 System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
             } finally {
@@ -342,4 +357,5 @@ public final class ComputerCraftAPI
     private static Method computerCraft_getDefaultBundledRedstoneOutput = null;
     private static Method computerCraft_registerMediaProvider = null;
     private static Method computerCraft_registerPermissionProvider = null;
+    private static Method computerCraft_registerPocketUpgrade = null;
 }
diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java
new file mode 100644
index 000000000..2485cacf3
--- /dev/null
+++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java
@@ -0,0 +1,77 @@
+package dan200.computercraft.api.pocket;
+
+import dan200.computercraft.api.peripheral.IPeripheral;
+import net.minecraft.entity.Entity;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.ResourceLocation;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Map;
+
+/**
+ * Wrapper class for pocket computers
+ */
+public interface IPocketAccess
+{
+    /**
+     * Gets the entity holding this item.
+     *
+     * @return The holding entity. This may be {@code null}.
+     */
+    @Nullable
+    Entity getEntity();
+
+    /**
+     * Get the colour of the pocket computer's light.
+     *
+     * See {@link #setLight(int)} for the values this may return.
+     *
+     * @return The colour of the pocket computer's light.
+     * @see #setLight(int)
+     */
+    int getLight();
+
+    /**
+     * Set the colour of the pocket computer's light. Use {@link 0} to turn it off.
+     *
+     * Colours take the form of an integer between 0 and 15, using the opposite order to those in
+     * {@link <a href="http://www.computercraft.info/wiki/Colors_(API)#Colors">The colors API</a>}  - so 0 being black,
+     * 1 representing red, 2 representing green all the way up to 15 for white.
+     *
+     * @param value The colour the light should have.
+     * @see #getLight()
+     */
+    void setLight( int value );
+
+    /**
+     * Get the upgrade-specific NBT.
+     *
+     * This is persisted between computer reboots and chunk loads.
+     *
+     * @return The upgrade's NBT.
+     * @see #updateUpgradeNBTData()
+     */
+    @Nonnull
+    NBTTagCompound getUpgradeNBTData();
+
+    /**
+     * Mark the upgrade-specific NBT as dirty.
+     *
+     * @see #getUpgradeNBTData()
+     */
+    void updateUpgradeNBTData();
+
+    /**
+     * Remove the current peripheral and create a new one. You may wish to do this if the methods available change.
+     */
+    void invalidatePeripheral();
+
+    /**
+     * Get a list of all upgrades for the pocket computer.
+     *
+     * @return A collection of all upgrade names.
+     */
+    @Nonnull
+    Map<ResourceLocation, IPeripheral> getUpgrades();
+}
diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java
new file mode 100644
index 000000000..4b92ac214
--- /dev/null
+++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java
@@ -0,0 +1,91 @@
+package dan200.computercraft.api.pocket;
+
+import dan200.computercraft.api.ComputerCraftAPI;
+import dan200.computercraft.api.peripheral.IPeripheral;
+import dan200.computercraft.api.turtle.ITurtleUpgrade;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.World;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Additional peripherals for pocket computers.
+ *
+ * This is similar to {@link dan200.computercraft.api.turtle.ITurtleUpgrade}.
+ */
+public interface IPocketUpgrade
+{
+
+    /**
+     * Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or
+     * "my_mod:my_upgrade".
+     *
+     * You should use a unique resource domain to ensure this upgrade is uniquely identified. The upgrade will fail
+     * registration if an already used ID is specified.
+     *
+     * @return The upgrade's id.
+     * @see IPocketUpgrade#getUpgradeID()
+     * @see ComputerCraftAPI#registerPocketUpgrade(IPocketUpgrade)
+     */
+    @Nonnull
+    ResourceLocation getUpgradeID();
+
+    /**
+     * Return an unlocalised string to describe the type of pocket computer this upgrade provides.
+     *
+     * An example of a built-in adjectives is "Wireless" - this is converted to "Wireless Pocket Computer".
+     *
+     * @return The unlocalised adjective.
+     * @see ITurtleUpgrade#getUnlocalisedAdjective()
+     */
+    @Nonnull
+    String getUnlocalisedAdjective();
+
+    /**
+     * Return an item stack representing the type of item that a pocket computer must be crafted with to create a
+     * pocket computer which holds this upgrade. This item stack is also used to determine the upgrade given by
+     * {@code pocket.equip()}/{@code pocket.unequip()}.
+     *
+     * @return The item stack used for crafting. This can be {@code null} if crafting is disabled.
+     */
+    @Nullable
+    ItemStack getCraftingItem();
+
+    /**
+     * Creates a peripheral for the pocket computer.
+     *
+     * The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to
+     * {@link #update(IPocketAccess, IPeripheral)} and will be attached, detached and have methods called in the same
+     * manner as an ordinary peripheral.
+     *
+     * @param access The access object for the pocket item stack.
+     * @return The newly created peripheral.
+     * @see #update(IPocketAccess, IPeripheral)
+     */
+    @Nullable
+    IPeripheral createPeripheral( @Nonnull IPocketAccess access );
+
+    /**
+     * Called when the pocket computer item stack updates.
+     *
+     * @param access     The access object for the pocket item stack.
+     * @param peripheral The peripheral for this upgrade.
+     * @see #createPeripheral(IPocketAccess)
+     */
+    void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral );
+
+    /**
+     * Called when the pocket computer is right clicked.
+     *
+     * @param world      The world the computer is in.
+     * @param access     The access object for the pocket item stack.
+     * @param peripheral The peripheral for this upgrade.
+     * @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path
+     * which returns {@code false}, such as requiring the player to be sneaking - otherwise they will be unable to
+     * access the GUI.
+     * @see #createPeripheral(IPocketAccess)
+     */
+    boolean onRightClick( @Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral );
+}
diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
index eb3366d1e..7dab83860 100644
--- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
+++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
@@ -25,6 +25,7 @@ import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
 import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
 import dan200.computercraft.shared.turtle.blocks.TileTurtle;
 import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
+import dan200.computercraft.shared.util.Colour;
 import net.minecraft.block.Block;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.renderer.GlStateManager;
@@ -53,7 +54,6 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 import net.minecraftforge.fml.common.gameevent.TickEvent;
 import net.minecraftforge.fml.relauncher.Side;
 import net.minecraftforge.fml.relauncher.SideOnly;
-import org.lwjgl.opengl.GL11;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -117,19 +117,14 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
             private ModelResourceLocation pocket_computer_off = new ModelResourceLocation( "computercraft:pocketComputer", "inventory" );
             private ModelResourceLocation pocket_computer_on = new ModelResourceLocation( "computercraft:pocket_computer_on", "inventory" );
             private ModelResourceLocation pocket_computer_blinking = new ModelResourceLocation( "computercraft:pocket_computer_blinking", "inventory" );
-            private ModelResourceLocation pocket_computer_on_modem_on = new ModelResourceLocation( "computercraft:pocket_computer_on_modem_on", "inventory" );
-            private ModelResourceLocation pocket_computer_blinking_modem_on = new ModelResourceLocation( "computercraft:pocket_computer_blinking_modem_on", "inventory" );
             private ModelResourceLocation advanced_pocket_computer_off = new ModelResourceLocation( "computercraft:advanced_pocket_computer_off", "inventory" );
             private ModelResourceLocation advanced_pocket_computer_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_on", "inventory" );
             private ModelResourceLocation advanced_pocket_computer_blinking = new ModelResourceLocation( "computercraft:advanced_pocket_computer_blinking", "inventory" );
-            private ModelResourceLocation advanced_pocket_computer_on_modem_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_on_modem_on", "inventory" );
-            private ModelResourceLocation advanced_pocket_computer_blinking_modem_on = new ModelResourceLocation( "computercraft:advanced_pocket_computer_blinking_modem_on", "inventory" );
 
             @Override
             public ModelResourceLocation getModelLocation( ItemStack stack )
             {
                 ItemPocketComputer itemPocketComputer = (ItemPocketComputer)stack.getItem();
-                boolean modemOn = itemPocketComputer.getModemState( stack );
                 switch( itemPocketComputer.getFamily( stack ) )
                 {
                     case Advanced:
@@ -143,11 +138,11 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
                             }
                             case On:
                             {
-                                return modemOn ? advanced_pocket_computer_on_modem_on : advanced_pocket_computer_on;
+                                return advanced_pocket_computer_on;
                             }
                             case Blinking:
                             {
-                                return modemOn ? advanced_pocket_computer_blinking_modem_on : advanced_pocket_computer_blinking;
+                                return advanced_pocket_computer_blinking;
                             }
                         }
                     }
@@ -163,24 +158,36 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
                             }
                             case On:
                             {
-                                return modemOn ? pocket_computer_on_modem_on : pocket_computer_on;
+                                return pocket_computer_on;
                             }
                             case Blinking:
                             {
-                                return modemOn ? pocket_computer_blinking_modem_on : pocket_computer_blinking;
+                                return pocket_computer_blinking;
                             }
                         }
                     }
                 }
             }
         }, new String[] {
-            "pocketComputer", "pocket_computer_on", "pocket_computer_blinking", "pocket_computer_on_modem_on", "pocket_computer_blinking_modem_on",
-            "advanced_pocket_computer_off", "advanced_pocket_computer_on", "advanced_pocket_computer_blinking", "advanced_pocket_computer_on_modem_on", "advanced_pocket_computer_blinking_modem_on",
+            "pocketComputer", "pocket_computer_on", "pocket_computer_blinking",
+            "advanced_pocket_computer_off", "advanced_pocket_computer_on", "advanced_pocket_computer_blinking",
         } );
 
         // Setup
-		mc.getItemColors().registerItemColorHandler(new DiskColorHandler(ComputerCraft.Items.disk), ComputerCraft.Items.disk);
-		mc.getItemColors().registerItemColorHandler(new DiskColorHandler(ComputerCraft.Items.diskExpanded), ComputerCraft.Items.diskExpanded);
+        mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.disk ), ComputerCraft.Items.disk );
+        mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.diskExpanded ), ComputerCraft.Items.diskExpanded );
+
+        mc.getItemColors().registerItemColorHandler( new IItemColor()
+        {
+            @Override
+            public int getColorFromItemstack( ItemStack stack, int layout )
+            {
+                if( layout != 1 ) return 0xFFFFFF;
+
+                Colour colour = Colour.fromInt( ComputerCraft.Items.pocketComputer.getLightState( stack ) );
+                return colour == null ? Colour.Black.getHex() : colour.getHex();
+            }
+        }, ComputerCraft.Items.pocketComputer );
 
         // Setup renderers
         ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() );
diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
index b3d6cf853..8ef404c0f 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
@@ -6,14 +6,26 @@
 
 package dan200.computercraft.shared.pocket.apis;
 
+import dan200.computercraft.ComputerCraft;
 import dan200.computercraft.api.lua.ILuaContext;
+import dan200.computercraft.api.lua.ILuaTask;
 import dan200.computercraft.api.lua.LuaException;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.core.apis.ILuaAPI;
+import dan200.computercraft.shared.pocket.core.PocketServerComputer;
+import dan200.computercraft.shared.util.InventoryUtil;
+import dan200.computercraft.shared.util.WorldUtil;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.InventoryPlayer;
+import net.minecraft.item.ItemStack;
 
 public class PocketAPI implements ILuaAPI
 {
-    public PocketAPI()
+    private final PocketServerComputer m_computer;
+
+    public PocketAPI( PocketServerComputer computer )
     {
+        this.m_computer = computer;
     }
 
     @Override
@@ -43,14 +55,123 @@ public class PocketAPI implements ILuaAPI
     public String[] getMethodNames()
     {
         return new String[] {
-            // TODO: Add some methods
+            "equipBack",
+            "unequipBack"
         };
     }
 
     @Override
-    public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException
+    public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException
     {
-        // TODO: Add some methods
+        switch( method )
+        {
+            case 0:
+                // equipBack
+                return context.executeMainThreadTask( new ILuaTask()
+                {
+                    @Override
+                    public Object[] execute() throws LuaException
+                    {
+                        if( !(m_computer.getEntity() instanceof EntityPlayer) )
+                        {
+                            throw new LuaException( "Cannot find player" );
+                        }
+
+                        EntityPlayer player = (EntityPlayer) m_computer.getEntity();
+                        InventoryPlayer inventory = player.inventory;
+
+                        IPocketUpgrade previousUpgrade = m_computer.getUpgrade();
+
+                        // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite
+                        // one. We start from the position the item is currently in and loop round to the start.
+                        IPocketUpgrade newUpgrade = findUpgrade( inventory.mainInventory, inventory.currentItem, previousUpgrade );
+                        if( newUpgrade == null )
+                        {
+                            newUpgrade = findUpgrade( inventory.offHandInventory, 0, previousUpgrade );
+                        }
+                        if( newUpgrade == null ) throw new LuaException( "Cannot find a valid upgrade" );
+
+                        // Remove the current upgrade
+                        if( previousUpgrade != null )
+                        {
+                            ItemStack stack = previousUpgrade.getCraftingItem();
+                            if( stack != null )
+                            {
+                                stack = InventoryUtil.storeItems( stack, inventory, 0, 36, inventory.currentItem );
+                                if( stack != null )
+                                {
+                                    WorldUtil.dropItemStack( stack, player.worldObj, player.posX, player.posY, player.posZ );
+                                }
+                            }
+                        }
+
+                        // Set the new upgrade
+                        m_computer.setUpgrade( newUpgrade );
+
+                        return null;
+                    }
+                } );
+
+            case 1:
+                // unequipBack
+                return context.executeMainThreadTask( new ILuaTask()
+                {
+                    @Override
+                    public Object[] execute() throws LuaException
+                    {
+                        if( !(m_computer.getEntity() instanceof EntityPlayer) )
+                        {
+                            throw new LuaException( "Cannot find player" );
+                        }
+
+                        EntityPlayer player = (EntityPlayer) m_computer.getEntity();
+                        InventoryPlayer inventory = player.inventory;
+
+                        IPocketUpgrade previousUpgrade = m_computer.getUpgrade();
+
+                        if( previousUpgrade == null ) throw new LuaException( "Nothing to unequip" );
+
+                        m_computer.setUpgrade( null );
+
+                        ItemStack stack = previousUpgrade.getCraftingItem();
+                        if( stack != null )
+                        {
+                            stack = InventoryUtil.storeItems( stack, inventory, 0, 36, inventory.currentItem );
+                            if( stack != null )
+                            {
+                                WorldUtil.dropItemStack( stack, player.worldObj, player.posX, player.posY, player.posZ );
+                            }
+                        }
+
+                        return null;
+                    }
+                } );
+            default:
+                return null;
+        }
+    }
+
+    private static IPocketUpgrade findUpgrade( ItemStack[] inv, int start, IPocketUpgrade previous )
+    {
+        for (int i = 0; i < inv.length; i++)
+        {
+            ItemStack invStack = inv[ (i + start) % inv.length ];
+            if( invStack != null )
+            {
+                IPocketUpgrade newUpgrade = ComputerCraft.getPocketUpgrade( invStack );
+
+                if( newUpgrade != null && newUpgrade != previous )
+                {
+                    // Consume an item from this stack and exit the loop
+                    invStack = invStack.copy();
+                    invStack.stackSize--;
+                    inv[ (i + start) % inv.length ] = invStack.stackSize <= 0 ? null : invStack;
+
+                    return newUpgrade;
+                }
+            }
+        }
+
         return null;
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java
new file mode 100644
index 000000000..bd0d9470c
--- /dev/null
+++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java
@@ -0,0 +1,141 @@
+package dan200.computercraft.shared.pocket.core;
+
+import dan200.computercraft.ComputerCraft;
+import dan200.computercraft.api.peripheral.IPeripheral;
+import dan200.computercraft.api.pocket.IPocketAccess;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
+import dan200.computercraft.shared.computer.core.ComputerFamily;
+import dan200.computercraft.shared.computer.core.ServerComputer;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.InventoryPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.World;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.Map;
+
+public class PocketServerComputer extends ServerComputer implements IPocketAccess
+{
+    private IPocketUpgrade m_upgrade;
+    private Entity m_entity;
+    private ItemStack m_stack;
+
+    public PocketServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family )
+    {
+        super( world, computerID, label, instanceID, family, ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer );
+    }
+
+    @Nullable
+    @Override
+    public Entity getEntity()
+    {
+        return m_entity;
+    }
+
+    @Override
+    public int getLight()
+    {
+        int value = getUserData().getInteger( "modemLight" );
+        return value >= 0 && value <= 15 ? value : 0;
+    }
+
+    @Override
+    public void setLight( int value )
+    {
+        if( value < 0 || value > 15 ) throw new IllegalArgumentException( "Colour out of bounds" );
+
+        NBTTagCompound tag = getUserData();
+        if( tag.getInteger( "modemLight" ) != value )
+        {
+            tag.setInteger( "modemLight", value );
+            updateUserData();
+        }
+    }
+
+    @Nonnull
+    @Override
+    public NBTTagCompound getUpgradeNBTData()
+    {
+        return ComputerCraft.Items.pocketComputer.getUpgradeInfo( m_stack );
+    }
+
+    @Override
+    public void updateUpgradeNBTData()
+    {
+        InventoryPlayer inventory = m_entity instanceof EntityPlayer ? ((EntityPlayer) m_entity).inventory : null;
+        if( inventory != null )
+        {
+            inventory.markDirty();
+        }
+    }
+
+    @Override
+    public void invalidatePeripheral()
+    {
+        IPeripheral peripheral = m_upgrade == null ? null : m_upgrade.createPeripheral( this );
+        setPeripheral( 2, peripheral );
+    }
+
+    @Nonnull
+    @Override
+    public Map<ResourceLocation, IPeripheral> getUpgrades()
+    {
+        if( m_upgrade == null )
+        {
+            return Collections.emptyMap();
+        }
+        else
+        {
+            return Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( 2 ) );
+        }
+    }
+
+    public IPocketUpgrade getUpgrade()
+    {
+        return m_upgrade;
+    }
+
+    /**
+     * Set the upgrade for this pocket computer, also updating the item stack.
+     *
+     * Note this method is not thread safe - it must be called from the server thread.
+     *
+     * @param upgrade The new upgrade to set it to, may be {@code null}.
+     */
+    public void setUpgrade( IPocketUpgrade upgrade )
+    {
+        if( this.m_upgrade == upgrade ) return;
+
+        synchronized (this)
+        {
+            ComputerCraft.Items.pocketComputer.setUpgrade( m_stack, upgrade );
+            if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty();
+
+            this.m_upgrade = upgrade;
+            invalidatePeripheral();
+        }
+    }
+
+    public synchronized void updateValues( Entity entity, ItemStack stack, IPocketUpgrade upgrade )
+    {
+        if( entity != null )
+        {
+            setWorld( entity.getEntityWorld() );
+            setPosition( entity.getPosition() );
+        }
+
+        m_entity = entity;
+        m_stack = stack;
+
+        if( this.m_upgrade != upgrade )
+        {
+            this.m_upgrade = upgrade;
+            invalidatePeripheral();
+        }
+    }
+}
diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
index 1044cbe37..0199f92b1 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
@@ -10,18 +10,17 @@ import com.google.common.base.Objects;
 import dan200.computercraft.ComputerCraft;
 import dan200.computercraft.api.filesystem.IMount;
 import dan200.computercraft.api.media.IMedia;
-import dan200.computercraft.api.peripheral.IPeripheral;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.shared.computer.blocks.ComputerState;
 import dan200.computercraft.shared.computer.core.ClientComputer;
 import dan200.computercraft.shared.computer.core.ComputerFamily;
 import dan200.computercraft.shared.computer.core.ServerComputer;
 import dan200.computercraft.shared.computer.items.IComputerItem;
 import dan200.computercraft.shared.pocket.apis.PocketAPI;
-import dan200.computercraft.shared.pocket.peripherals.PocketModemPeripheral;
+import dan200.computercraft.shared.pocket.core.PocketServerComputer;
 import dan200.computercraft.shared.util.StringUtil;
 import net.minecraft.creativetab.CreativeTabs;
 import net.minecraft.entity.Entity;
-import net.minecraft.entity.EntityLivingBase;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.inventory.IInventory;
 import net.minecraft.item.Item;
@@ -32,11 +31,12 @@ import net.minecraft.util.EnumActionResult;
 import net.minecraft.util.EnumHand;
 import net.minecraft.util.SoundEvent;
 import net.minecraft.world.World;
+import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.fml.relauncher.Side;
+import net.minecraftforge.fml.relauncher.SideOnly;
 
 import java.util.List;
 
-;
-
 public class ItemPocketComputer extends Item implements IComputerItem, IMedia
 {
     public ItemPocketComputer()
@@ -47,7 +47,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         setCreativeTab( ComputerCraft.mainCreativeTab );
     }
 
-    public ItemStack create( int id, String label, ComputerFamily family, boolean modem )
+    public ItemStack create( int id, String label, ComputerFamily family, IPocketUpgrade upgrade )
     {
         // Ignore types we can't handle
         if( family != ComputerFamily.Normal && family != ComputerFamily.Advanced )
@@ -58,16 +58,16 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         // Build the stack
         int damage = (family == ComputerFamily.Advanced) ? 1 : 0;
         ItemStack result = new ItemStack( this, 1, damage );
-        if( id >= 0 || modem )
+        if( id >= 0 || upgrade != null )
         {
             NBTTagCompound compound = new NBTTagCompound();
             if( id >= 0 )
             {
                 compound.setInteger( "computerID", id );
             }
-            if( modem )
+            if( upgrade != null )
             {
-                compound.setInteger( "upgrade", 1 );
+                compound.setString( "upgrade", upgrade.getUpgradeID().toString() );
             }
             result.setTagCompound( compound );
         }
@@ -79,12 +79,19 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
     }
 
     @Override
-    public void getSubItems( Item itemID, CreativeTabs tabs, List list )
+    public void getSubItems( Item itemID, CreativeTabs tabs, List<ItemStack> list )
     {
-        list.add( PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, false ) );
-        list.add( PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, true ) );
-        list.add( PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, false ) );
-        list.add( PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, true ) );
+        getSubItems( list, ComputerFamily.Normal );
+        getSubItems( list, ComputerFamily.Advanced );
+    }
+
+    private void getSubItems( List<ItemStack> list, ComputerFamily family )
+    {
+        list.add( PocketComputerItemFactory.create( -1, null, family, null ) );
+        for (IPocketUpgrade upgrade : ComputerCraft.getVanillaPocketUpgrades())
+        {
+            list.add( PocketComputerItemFactory.create( -1, null, family, upgrade ) );
+        }
     }
 
     @Override
@@ -93,13 +100,16 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         if( !world.isRemote )
         {
             // Server side
-            IInventory inventory = (entity instanceof EntityPlayer) ? ((EntityPlayer)entity).inventory : null;
-            ServerComputer computer = createServerComputer( world, inventory, stack );
+            IInventory inventory = (entity instanceof EntityPlayer) ? ((EntityPlayer) entity).inventory : null;
+            PocketServerComputer computer = createServerComputer( world, inventory, entity, stack );
             if( computer != null )
             {
+                IPocketUpgrade upgrade = getUpgrade( stack );
+
                 // Ping computer
                 computer.keepAlive();
                 computer.setWorld( world );
+                computer.updateValues( entity, stack, upgrade );
 
                 // Sync ID
                 int id = computer.getID();
@@ -123,30 +133,10 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
                     }
                 }
 
-                // Update modem
-                IPeripheral peripheral = computer.getPeripheral( 2 );
-                if( peripheral != null && peripheral instanceof PocketModemPeripheral )
+                // Update pocket upgrade
+                if( upgrade != null )
                 {
-                    // Location
-                    PocketModemPeripheral modem = (PocketModemPeripheral)peripheral;
-                    if( entity instanceof EntityLivingBase )
-                    {
-                        EntityLivingBase player = (EntityLivingBase)entity;
-                        modem.setLocation( world, player.posX, player.posY + player.getEyeHeight(), player.posZ );
-                    }
-                    else
-                    {
-                        modem.setLocation( world, entity.posX, entity.posY, entity.posZ );
-                    }
-
-                    // Light
-                    boolean modemLight = modem.isActive();
-                    NBTTagCompound modemNBT = computer.getUserData();
-                    if( modemNBT.getBoolean( "modemLight" ) != modemLight )
-                    {
-                        modemNBT.setBoolean( "modemLight", modemLight );
-                        computer.updateUserData();
-                    }
+                    upgrade.update( computer, computer.getPeripheral( 2 ) );
                 }
             }
         }
@@ -166,12 +156,22 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
     {
         if( !world.isRemote )
         {
-            ServerComputer computer = createServerComputer( world, player.inventory, stack );
+            PocketServerComputer computer = createServerComputer( world, player.inventory, player, stack );
+
+            boolean stop = false;
             if( computer != null )
             {
                 computer.turnOn();
+
+                IPocketUpgrade upgrade = getUpgrade( stack );
+                if( upgrade != null )
+                {
+                    computer.updateValues( player, stack, upgrade );
+                    stop = upgrade.onRightClick( world, computer, computer.getPeripheral( 2 ) );
+                }
             }
-            ComputerCraft.openPocketComputerGUI( player, hand );
+
+            if( !stop ) ComputerCraft.openPocketComputerGUI( player, hand );
         }
         return new ActionResult<ItemStack>( EnumActionResult.SUCCESS, stack );
     }
@@ -197,12 +197,12 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
     public String getItemStackDisplayName( ItemStack stack )
     {
         String baseString = getUnlocalizedName( stack );
-        boolean modem = getHasModem( stack );
-        if( modem )
+        IPocketUpgrade upgrade = getUpgrade( stack );
+        if( upgrade != null )
         {
             return StringUtil.translateToLocalFormatted(
                 baseString + ".upgraded.name",
-                StringUtil.translateToLocal( "upgrade.computercraft:wireless_modem.adjective" )
+                StringUtil.translateToLocal( upgrade.getUnlocalisedAdjective() )
             );
         }
         else
@@ -224,14 +224,14 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         }
     }
 
-    private ServerComputer createServerComputer( final World world, IInventory inventory, ItemStack stack )
+    private PocketServerComputer createServerComputer( final World world, IInventory inventory, Entity entity, ItemStack stack )
     {
         if( world.isRemote )
         {
             return null;
         }
 
-        ServerComputer computer;
+        PocketServerComputer computer;
         int instanceID = getInstanceID( stack );
         int sessionID = getSessionID( stack );
         int correctSessionID = ComputerCraft.serverComputerRegistry.getSessionID();
@@ -239,7 +239,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         if( instanceID >= 0 && sessionID == correctSessionID &&
             ComputerCraft.serverComputerRegistry.contains( instanceID ) )
         {
-            computer = ComputerCraft.serverComputerRegistry.get( instanceID );
+            computer = (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID );
         }
         else
         {
@@ -255,20 +255,15 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
                 computerID = ComputerCraft.createUniqueNumberedSaveDir( world, "computer" );
                 setComputerID( stack, computerID );
             }
-            computer = new ServerComputer(
+            computer = new PocketServerComputer(
                 world,
                 computerID,
                 getLabel( stack ),
                 instanceID,
-                getFamily( stack ),
-                ComputerCraft.terminalWidth_pocketComputer,
-                ComputerCraft.terminalHeight_pocketComputer
+                getFamily( stack )
             );
-            computer.addAPI( new PocketAPI() );
-            if( getHasModem( stack ) )
-            {
-                computer.setPeripheral( 2, new PocketModemPeripheral( false ) );
-            }
+            computer.updateValues( entity, stack, getUpgrade( stack ) );
+            computer.addAPI( new PocketAPI( computer ) );
             ComputerCraft.serverComputerRegistry.add( instanceID, computer );
             if( inventory != null )
             {
@@ -394,7 +389,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
     @Override
     public IMount createDataMount( ItemStack stack, World world )
     {
-        ServerComputer computer = createServerComputer( world, null, stack );
+        ServerComputer computer = createServerComputer( world, null, null, stack );
         if( computer != null )
         {
             return computer.getRootMount();
@@ -440,6 +435,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         stack.getTagCompound().setInteger( "sessionID", sessionID );
     }
 
+    @SideOnly(Side.CLIENT)
     public ComputerState getState( ItemStack stack )
     {
         ClientComputer computer = getClientComputer( stack );
@@ -450,27 +446,79 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia
         return ComputerState.Off;
     }
 
-    public boolean getModemState( ItemStack stack )
+    @SideOnly(Side.CLIENT)
+    public int getLightState( ItemStack stack )
     {
         ClientComputer computer = getClientComputer( stack );
         if( computer != null && computer.isOn() )
         {
             NBTTagCompound computerNBT = computer.getUserData();
-            if( computerNBT != null && computerNBT.getBoolean( "modemLight" ) )
+            if( computerNBT != null )
             {
-                return true;
+                return computerNBT.getInteger( "modemLight" );
             }
         }
-        return false;
+        return 0;
     }
 
-    public boolean getHasModem( ItemStack stack )
+    public IPocketUpgrade getUpgrade( ItemStack stack )
     {
         NBTTagCompound compound = stack.getTagCompound();
-        if( compound != null && compound.hasKey( "upgrade" ) )
+        if( compound != null )
         {
-            return (compound.getInteger( "upgrade" ) == 1);
+            if( compound.hasKey( "upgrade", Constants.NBT.TAG_STRING ) )
+            {
+                String name = compound.getString( "upgrade" );
+                return ComputerCraft.getPocketUpgrade( name );
+            }
+            else if( compound.hasKey( "upgrade", Constants.NBT.TAG_ANY_NUMERIC ) )
+            {
+                int id = compound.getInteger( "upgrade" );
+                if( id == 1 )
+                {
+                    return ComputerCraft.getPocketUpgrade( "computercraft:wireless_modem" );
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public void setUpgrade( ItemStack stack, IPocketUpgrade upgrade )
+    {
+        NBTTagCompound compound = stack.getTagCompound();
+        if( compound == null ) stack.setTagCompound( compound = new NBTTagCompound() );
+
+        if( upgrade == null )
+        {
+            compound.removeTag( "upgrade" );
+        }
+        else
+        {
+            compound.setString( "upgrade", upgrade.getUpgradeID().toString() );
+        }
+
+        compound.removeTag( "upgrade_info" );
+    }
+
+    public NBTTagCompound getUpgradeInfo( ItemStack stack )
+    {
+        NBTTagCompound tag = stack.getTagCompound();
+        if( tag == null )
+        {
+            tag = new NBTTagCompound();
+            stack.setTagCompound( tag );
+        }
+
+        if( tag.hasKey( "upgrade_info", Constants.NBT.TAG_COMPOUND ) )
+        {
+            return tag.getCompoundTag( "upgrade_info" );
+        }
+        else
+        {
+            NBTTagCompound sub = new NBTTagCompound();
+            tag.setTag( "upgrade_info", sub );
+            return sub;
         }
-        return false;
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java
index 2b17d6555..2fa08d038 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java
@@ -7,12 +7,13 @@
 package dan200.computercraft.shared.pocket.items;
 
 import dan200.computercraft.ComputerCraft;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.shared.computer.core.ComputerFamily;
 import net.minecraft.item.ItemStack;
 
 public class PocketComputerItemFactory
 {
-    public static ItemStack create( int id, String label, ComputerFamily family, boolean modem )
+    public static ItemStack create( int id, String label, ComputerFamily family, IPocketUpgrade upgrade )
     {
         ItemPocketComputer computer = ComputerCraft.Items.pocketComputer;
         switch( family )
@@ -20,7 +21,7 @@ public class PocketComputerItemFactory
             case Normal:
             case Advanced:
             {
-                return computer.create( id, label, family, modem );
+                return computer.create( id, label, family, upgrade );
             }
         }
         return null;
diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java
new file mode 100644
index 000000000..8d58a8365
--- /dev/null
+++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java
@@ -0,0 +1,89 @@
+package dan200.computercraft.shared.pocket.peripherals;
+
+import dan200.computercraft.api.peripheral.IPeripheral;
+import dan200.computercraft.api.pocket.IPocketAccess;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
+import dan200.computercraft.shared.peripheral.PeripheralType;
+import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
+import dan200.computercraft.shared.util.Colour;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.World;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class PocketModem implements IPocketUpgrade
+{
+    private final boolean m_advanced;
+
+    public PocketModem( boolean m_advanced )
+    {
+        this.m_advanced = m_advanced;
+    }
+
+    @Nonnull
+    @Override
+    public ResourceLocation getUpgradeID()
+    {
+        return m_advanced
+            ? new ResourceLocation( "computercraft", "advanved_modem" )
+            : new ResourceLocation( "computercraft", "wireless_modem" );
+    }
+
+    @Nonnull
+    @Override
+    public String getUnlocalisedAdjective()
+    {
+        return m_advanced
+            ? "upgrade.computercraft:advanced_modem.adjective"
+            : "upgrade.computercraft:wireless_modem.adjective";
+    }
+
+    @Nullable
+    @Override
+    public ItemStack getCraftingItem()
+    {
+        return PeripheralItemFactory.create(
+            m_advanced ? PeripheralType.AdvancedModem : PeripheralType.WirelessModem,
+            null, 1
+        );
+    }
+
+    @Nullable
+    @Override
+    public IPeripheral createPeripheral( @Nonnull IPocketAccess access )
+    {
+        return new PocketModemPeripheral( m_advanced );
+    }
+
+    @Override
+    public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
+    {
+        if( peripheral instanceof PocketModemPeripheral )
+        {
+            Entity entity = access.getEntity();
+
+            PocketModemPeripheral modem = (PocketModemPeripheral) peripheral;
+            if( entity instanceof EntityLivingBase )
+            {
+                EntityLivingBase player = (EntityLivingBase) entity;
+                modem.setLocation( entity.getEntityWorld(), player.posX, player.posY + player.getEyeHeight(), player.posZ );
+            }
+            else if( entity != null )
+            {
+                modem.setLocation( entity.getEntityWorld(), entity.posX, entity.posY, entity.posZ );
+            }
+
+            access.setLight( modem.isActive() ? Colour.Red.ordinal() : Colour.Black.ordinal() );
+        }
+    }
+
+    @Override
+    public boolean onRightClick( @Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral )
+    {
+        return false;
+    }
+}
diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
index a78623538..7eeefef94 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
@@ -6,9 +6,9 @@
 
 package dan200.computercraft.shared.pocket.recipes;
 
+import dan200.computercraft.ComputerCraft;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.shared.computer.core.ComputerFamily;
-import dan200.computercraft.shared.peripheral.PeripheralType;
-import dan200.computercraft.shared.peripheral.common.IPeripheralItem;
 import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
 import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
 import net.minecraft.inventory.InventoryCrafting;
@@ -31,7 +31,7 @@ public class PocketComputerUpgradeRecipe implements IRecipe
     @Override
     public ItemStack getRecipeOutput()
     {
-        return PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, true );
+        return PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, null );
     }
 
     @Override
@@ -47,9 +47,9 @@ public class PocketComputerUpgradeRecipe implements IRecipe
         ItemStack computer = null;
         int computerX = -1;
         int computerY = -1;
-        for( int y=0; y<inventory.getHeight(); ++y )
+        for (int y = 0; y < inventory.getHeight(); ++y)
         {
-            for( int x=0; x<inventory.getWidth(); ++x )
+            for (int x = 0; x < inventory.getWidth(); ++x)
             {
                 ItemStack item = inventory.getStackInRowAndColumn( x, y );
                 if( item != null && item.getItem() instanceof ItemPocketComputer )
@@ -71,11 +71,17 @@ public class PocketComputerUpgradeRecipe implements IRecipe
             return null;
         }
 
-        // Check for upgrades around the item
-        ItemStack upgrade = null;
-        for( int y=0; y<inventory.getHeight(); ++y )
+        ItemPocketComputer itemComputer = (ItemPocketComputer)computer.getItem();
+        if( itemComputer.getUpgrade( computer ) != null )
         {
-            for( int x=0; x<inventory.getWidth(); ++x )
+            return null;
+        }
+
+        // Check for upgrades around the item
+        IPocketUpgrade upgrade = null;
+        for (int y = 0; y < inventory.getHeight(); ++y)
+        {
+            for (int x = 0; x < inventory.getWidth(); ++x)
             {
                 ItemStack item = inventory.getStackInRowAndColumn( x, y );
                 if( x == computerX && y == computerY )
@@ -84,22 +90,12 @@ public class PocketComputerUpgradeRecipe implements IRecipe
                 }
                 else if( x == computerX && y == computerY - 1 )
                 {
-                    if( item != null && item.getItem() instanceof IPeripheralItem &&
-                        ((IPeripheralItem)item.getItem()).getPeripheralType( item ) == PeripheralType.WirelessModem )
-                    {
-                        upgrade = item;
-                    }
-                    else
-                    {
-                        return null;
-                    }
+                    upgrade = ComputerCraft.getPocketUpgrade( item );
+                    if( upgrade == null ) return null;
                 }
-                else
+                else if( item != null )
                 {
-                    if( item != null )
-                    {
-                        return null;
-                    }
+                    return null;
                 }
             }
         }
@@ -109,18 +105,11 @@ public class PocketComputerUpgradeRecipe implements IRecipe
             return null;
         }
 
-        // At this point we have a computer + 1 upgrade
-        ItemPocketComputer itemComputer = (ItemPocketComputer)computer.getItem();
-        if( itemComputer.getHasModem( computer ) )
-        {
-            return null;
-        }
-
         // Construct the new stack
         ComputerFamily family = itemComputer.getFamily( computer );
         int computerID = itemComputer.getComputerID( computer );
         String label = itemComputer.getLabel( computer );
-        return PocketComputerItemFactory.create( computerID, label, family, true );
+        return PocketComputerItemFactory.create( computerID, label, family, upgrade );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
index d6037bc10..369d8f94e 100644
--- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
+++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
@@ -8,6 +8,7 @@ package dan200.computercraft.shared.proxy;
 
 import dan200.computercraft.ComputerCraft;
 import dan200.computercraft.api.ComputerCraftAPI;
+import dan200.computercraft.api.pocket.IPocketUpgrade;
 import dan200.computercraft.core.computer.MainThread;
 import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
 import dan200.computercraft.shared.common.TileGeneric;
@@ -45,6 +46,7 @@ import dan200.computercraft.shared.peripheral.printer.TilePrinter;
 import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
 import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
 import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
+import dan200.computercraft.shared.pocket.peripherals.PocketModem;
 import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
 import dan200.computercraft.shared.turtle.blocks.TileTurtle;
 import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
@@ -410,7 +412,7 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
         GameRegistry.addRecipe( new ImpostorShapelessRecipe( bookPrintout, new Object[]{leather, singlePrintout, string} ) );
 
         // Pocket Computer
-        ItemStack pocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, false );
+        ItemStack pocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, null );
         GameRegistry.addRecipe( pocketComputer,
                 "XXX", "XYX", "XZX",
                 'X', Blocks.STONE,
@@ -419,7 +421,7 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
         );
 
         // Advanced Pocket Computer
-        ItemStack advancedPocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, false );
+        ItemStack advancedPocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, null );
         GameRegistry.addRecipe( advancedPocketComputer,
                 "XXX", "XYX", "XZX",
                 'X', Items.GOLD_INGOT,
@@ -427,16 +429,30 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
                 'Z', Blocks.GLASS_PANE
         );
 
+        // Register pocket upgrades
+        ComputerCraft.PocketUpgrades.wirelessModem = new PocketModem( false );
+        ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.wirelessModem );
+        ComputerCraft.PocketUpgrades.advancedModem = new PocketModem( true );
+        ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.advancedModem );
+
         // Wireless Pocket Computer
-        ItemStack wirelessPocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, true );
         GameRegistry.addRecipe( new PocketComputerUpgradeRecipe() );
 
-        // Advanced Wireless Pocket Computer
-        ItemStack advancedWirelessPocketComputer = PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, true );
-
         // Impostor Pocket Computer recipes (to fool NEI)
-        GameRegistry.addRecipe( new ImpostorRecipe( 1, 2, new ItemStack[]{wirelessModem, pocketComputer}, wirelessPocketComputer ) );
-        GameRegistry.addRecipe( new ImpostorRecipe( 1, 2, new ItemStack[]{wirelessModem, advancedPocketComputer}, advancedWirelessPocketComputer ) );
+        for (IPocketUpgrade upgrade : ComputerCraft.getVanillaPocketUpgrades())
+        {
+            GameRegistry.addRecipe( new ImpostorRecipe(
+                1, 2,
+                new ItemStack[]{ upgrade.getCraftingItem(), pocketComputer },
+                PocketComputerItemFactory.create( -1, null, ComputerFamily.Normal, upgrade )
+            ) );
+
+            GameRegistry.addRecipe( new ImpostorRecipe(
+                1, 2,
+                new ItemStack[]{ upgrade.getCraftingItem(), advancedPocketComputer },
+                PocketComputerItemFactory.create( -1, null, ComputerFamily.Advanced, upgrade )
+            ) );
+        }
 
         // Skulls (Easter Egg)
         // Dan
diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog b/src/main/resources/assets/computercraft/lua/rom/help/changelog
index 76d4ab0b0..7b8ede788 100644
--- a/src/main/resources/assets/computercraft/lua/rom/help/changelog
+++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog
@@ -6,6 +6,8 @@ New Features in ComputerCraft 1.80:
 * os.time() and os.day() now accept parameters to give the real world time.
 * Added os.epoch()
 * Monitor text now glows in the dark.
+* Added a "Pocket Computer upgrde API" so mod developers can add their own pocket upgrades.
+* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.
 
 New Features in ComputerCraft 1.79:
 
diff --git a/src/main/resources/assets/computercraft/lua/rom/help/pocket b/src/main/resources/assets/computercraft/lua/rom/help/pocket
new file mode 100644
index 000000000..fc498c669
--- /dev/null
+++ b/src/main/resources/assets/computercraft/lua/rom/help/pocket
@@ -0,0 +1,6 @@
+pocket is an API available on pocket computers, which allows modifying its upgrades.
+Functions in the pocket API:
+pocket.equipBack()
+pocket.unequipBack()
+
+When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand.
\ No newline at end of file
diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew
index 7dc6f17ce..bd8220b3f 100644
--- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew
+++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew
@@ -6,5 +6,7 @@ New Features in ComputerCraft 1.80:
 * os.time() and os.day() now accept parameters to give the real world time.
 * Added os.epoch()
 * Monitor text now glows in the dark.
+* Added a "Pocket Computer upgrde API" so mod developers can add their own pocket upgrades.
+* Added pocket.equipBack()/pocket.unequipBack() to add/remove pocket upgrades.
 
 Type "help changelog" to see the full version history.
diff --git a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking.json b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking.json
index 44d6ba418..784b5a5cd 100644
--- a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking.json
+++ b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking.json
@@ -1,6 +1,7 @@
 {
     "parent": "item/generated",
     "textures": {
-        "layer0": "computercraft:items/pocketComputerBlinkAdvanced"
+        "layer0": "computercraft:items/pocketComputerBlinkAdvanced",
+        "layer1": "computercraft:items/pocketComputerLight"
     }
 }
diff --git a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking_modem_on.json b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking_modem_on.json
deleted file mode 100644
index e7a01ae0b..000000000
--- a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_blinking_modem_on.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "parent": "item/generated",
-    "textures": {
-        "layer0": "computercraft:items/pocketComputerBlinkAdvanced",
-        "layer1": "computercraft:items/pocketComputerModemLight"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on.json b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on.json
index 5edc838c8..c3ce43796 100644
--- a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on.json
+++ b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on.json
@@ -1,6 +1,7 @@
 {
     "parent": "item/generated",
     "textures": {
-        "layer0": "computercraft:items/pocketComputerOnAdvanced"
+        "layer0": "computercraft:items/pocketComputerOnAdvanced",
+        "layer1": "computercraft:items/pocketComputerLight"
     }
 }
diff --git a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on_modem_on.json b/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on_modem_on.json
deleted file mode 100644
index da39d266c..000000000
--- a/src/main/resources/assets/computercraft/models/item/advanced_pocket_computer_on_modem_on.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "parent": "item/generated",
-    "textures": {
-        "layer0": "computercraft:items/pocketComputerOnAdvanced",
-        "layer1": "computercraft:items/pocketComputerModemLight"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking.json b/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking.json
index 2600d8049..7309710cb 100644
--- a/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking.json
+++ b/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking.json
@@ -1,6 +1,7 @@
 {
     "parent": "item/generated",
     "textures": {
-        "layer0": "computercraft:items/pocketComputerBlink"
+        "layer0": "computercraft:items/pocketComputerBlink",
+        "layer1": "computercraft:items/pocketComputerLight"
     }
 }
diff --git a/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking_modem_on.json b/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking_modem_on.json
deleted file mode 100644
index 47a53343b..000000000
--- a/src/main/resources/assets/computercraft/models/item/pocket_computer_blinking_modem_on.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "parent": "item/generated",
-    "textures": {
-        "layer0": "computercraft:items/pocketComputerBlink",
-        "layer1": "computercraft:items/pocketComputerModemLight"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/item/pocket_computer_on.json b/src/main/resources/assets/computercraft/models/item/pocket_computer_on.json
index 6c7c827ea..9575e139a 100644
--- a/src/main/resources/assets/computercraft/models/item/pocket_computer_on.json
+++ b/src/main/resources/assets/computercraft/models/item/pocket_computer_on.json
@@ -1,6 +1,7 @@
 {
     "parent": "item/generated",
     "textures": {
-        "layer0": "computercraft:items/pocketComputerOn"
+        "layer0": "computercraft:items/pocketComputerOn",
+        "layer1": "computercraft:items/pocketComputerLight"
     }
 }
diff --git a/src/main/resources/assets/computercraft/models/item/pocket_computer_on_modem_on.json b/src/main/resources/assets/computercraft/models/item/pocket_computer_on_modem_on.json
deleted file mode 100644
index a08912c00..000000000
--- a/src/main/resources/assets/computercraft/models/item/pocket_computer_on_modem_on.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "parent": "item/generated",
-    "textures": {
-        "layer0": "computercraft:items/pocketComputerOn",
-        "layer1": "computercraft:items/pocketComputerModemLight"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/textures/items/pocketComputerLight.png b/src/main/resources/assets/computercraft/textures/items/pocketComputerLight.png
new file mode 100644
index 000000000..52f186fc7
Binary files /dev/null and b/src/main/resources/assets/computercraft/textures/items/pocketComputerLight.png differ
diff --git a/src/main/resources/assets/computercraft/textures/items/pocketComputerModemLight.png b/src/main/resources/assets/computercraft/textures/items/pocketComputerModemLight.png
deleted file mode 100644
index 42238aafd..000000000
Binary files a/src/main/resources/assets/computercraft/textures/items/pocketComputerModemLight.png and /dev/null differ