Skip to content

Commit

Permalink
Merge pull request #807 from brentru/force-mcp
Browse files Browse the repository at this point in the history
Add support for "fake" MCP2221
  • Loading branch information
makermelissa committed Apr 5, 2024
2 parents 48d6a29 + 9f4b4a3 commit 2e47afc
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 13 deletions.
13 changes: 13 additions & 0 deletions src/adafruit_blinka/board/fake_microchip_mcp2221.py
@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""Pin definitions for the MicroChip MCP2221"""
from adafruit_blinka.microcontroller.fake_mcp2221 import pin

G0 = pin.G0
G1 = pin.G1
G2 = pin.G2
G3 = pin.G3

SCL = pin.SCL
SDA = pin.SDA
Empty file.
57 changes: 57 additions & 0 deletions src/adafruit_blinka/microcontroller/fake_mcp2221/analogio.py
@@ -0,0 +1,57 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`analogio` - Analog input and output control
=================================================
See `CircuitPython:analogio` in CircuitPython for more details.
* Author(s): Carter Nelson
"""

from adafruit_blinka.microcontroller.fake_mcp2221.pin import Pin
from adafruit_blinka import ContextManaged


class AnalogIn(ContextManaged):
"""Analog Input Class"""

def __init__(self, pin):
self._pin = Pin(pin.id)
self._pin.init(mode=Pin.ADC)

@property
def value(self):
"""Read the ADC and return the value"""
return self._pin.value()

# pylint: disable=no-self-use
@value.setter
def value(self, value):
# emulate what CircuitPython does
raise AttributeError("'AnalogIn' object has no attribute 'value'")

# pylint: enable=no-self-use

def deinit(self):
del self._pin


class AnalogOut(ContextManaged):
"""Analog Output Class"""

def __init__(self, pin):
self._pin = Pin(pin.id)
self._pin.init(mode=Pin.DAC)

@property
def value(self):
"""Return an error. This is output only."""
# emulate what CircuitPython does
raise AttributeError("unreadable attribute")

@value.setter
def value(self, value):
self._pin.value(value)

def deinit(self):
del self._pin
20 changes: 20 additions & 0 deletions src/adafruit_blinka/microcontroller/fake_mcp2221/fake_mcp2221.py
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""Chip Definition for MCP2221"""


class MCP2221:
"""MCP2221 Device Class Definition"""

def __init__(self):
pass # This is a "fake" implementation

def __del__(self):
# try to close the device before destroying the instance
return

# pylint: enable=unused-argument


mcp2221 = MCP2221()
30 changes: 30 additions & 0 deletions src/adafruit_blinka/microcontroller/fake_mcp2221/i2c.py
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""I2C Class for MCP2221"""
import random
from .fake_mcp2221 import mcp2221


class I2C:
"""Custom I2C Class for MCP2221"""

def __init__(self, *, frequency=100000):
self._mcp2221 = mcp2221
self._freq = frequency

@staticmethod
def scan(address_list=None):
"""Mocks an I2C scan.
If address_list is not provided, this function returns a
list of 3 randomly generated I2C addresses from 0x0 to 0x79.
For a stimulus-driven test: If address_list is provided,
this function returns the provided address_list.
"""
if address_list is None:
# Generate a list of 3 randomly generated addresses from 0x0 to 0x79
address_list = []
for _ in range(3):
address_list.append(random.randint(0x0, 0x79))
return address_list
return address_list
95 changes: 95 additions & 0 deletions src/adafruit_blinka/microcontroller/fake_mcp2221/pin.py
@@ -0,0 +1,95 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""fake_mcp2221 pin names"""
import random


class Pin:
"""A basic Pin class for use with a "fake" MCP2221."""

# pin modes
OUT = 0
IN = 1
ADC = 2
DAC = 3
# pin values
LOW = 0
HIGH = 1

def __init__(self, pin_id=None):
self.id = pin_id
self._mode = None
self._prv_val = False

def init(self, mode=IN, pull=None):
"""Initialize the Pin"""
if self.id is None:
raise RuntimeError("Can not init a None type pin.")
if pull is not None:
raise NotImplementedError("Internal pullups and pulldowns not supported")
if mode in (Pin.IN, Pin.OUT):
# All pins can do GPIO
# mcp2221.gp_set_mode(self.id, mcp2221.GP_GPIO)
# mcp2221.gpio_set_direction(self.id, mode)
self._mode = mode
elif mode == Pin.ADC:
# ADC only available on these pins
if self.id not in (1, 2, 3):
raise ValueError("Pin does not have ADC capabilities")
# mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT0)
# mcp2221.adc_configure()
elif mode == Pin.DAC:
# DAC only available on these pins
if self.id not in (2, 3):
raise ValueError("Pin does not have DAC capabilities")
# mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT1)
# mcp2221.dac_configure()
else:
raise ValueError("Incorrect pin mode: {}".format(mode))
self._mode = mode

def value(self, val=None):
"""Set or return the Pin Value"""
# Digital In / Out
if self._mode in (Pin.IN, Pin.OUT):
# digital read
if val is None:
# The returned value toggles between True and false
self._prv_val = not self._prv_val
return self._prv_val
# digital write
if val in (Pin.LOW, Pin.HIGH):
# We don't need to do anything here - no data is produced
return None
# nope
raise ValueError("Invalid value for pin.")
# Analog In
if self._mode == Pin.ADC:
if val is None:
# Returned value is between 0 and 65535 inclusive
# https://docs.circuitpython.org/en/latest/shared-bindings/analogio/index.html#analogio.AnalogIn.value
self._prv_val = random.randint(0, 65535)
return self._prv_val
# read only
raise AttributeError("'AnalogIn' object has no attribute 'value'")
# Analog Out
if self._mode == Pin.DAC:
if val is None:
# write only
raise AttributeError("unreadable attribute")
# We don't write to the DAC as this is a "fake" implementation
return None
raise RuntimeError(
"No action for mode {} with value {}".format(self._mode, val)
)


# create pin instances for each pin
G0 = Pin(0)
G1 = Pin(1)
G2 = Pin(2)
G3 = Pin(3)

SCL = Pin()
SDA = Pin()
13 changes: 10 additions & 3 deletions src/analogio.py
Expand Up @@ -9,16 +9,23 @@
* Author(s): Carter Nelson, Melissa LeBlanc-Williams
"""

import os
import sys

from adafruit_blinka.agnostic import detector

# pylint: disable=ungrouped-imports,wrong-import-position,unused-import

if detector.board.microchip_mcp2221:
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogIn
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogOut
if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.microcontroller.fake_mcp2221.analogio import AnalogIn
from adafruit_blinka.microcontroller.fake_mcp2221.analogio import AnalogOut
else:
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogIn
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogOut
elif detector.board.greatfet_one:
from adafruit_blinka.microcontroller.nxp_lpc4330.analogio import AnalogIn
from adafruit_blinka.microcontroller.nxp_lpc4330.analogio import AnalogOut
Expand Down
10 changes: 8 additions & 2 deletions src/board.py
Expand Up @@ -17,7 +17,7 @@


import sys

import os
import adafruit_platformdetect.constants.boards as ap_board
from adafruit_blinka.agnostic import board_id, detector

Expand Down Expand Up @@ -224,7 +224,13 @@
from adafruit_blinka.board.binho_nova import *

elif board_id == ap_board.MICROCHIP_MCP2221:
from adafruit_blinka.board.microchip_mcp2221 import *
if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.board.fake_microchip_mcp2221 import *
else:
from adafruit_blinka.board.microchip_mcp2221 import *

elif board_id == ap_board.GREATFET_ONE:
from adafruit_blinka.board.greatfet_one import *
Expand Down
10 changes: 8 additions & 2 deletions src/busio.py
Expand Up @@ -9,6 +9,7 @@
* Author(s): cefn
"""
import os

try:
import threading
Expand Down Expand Up @@ -50,8 +51,13 @@ def init(self, scl, sda, frequency):
self._i2c = _I2C(frequency=frequency)
return
if detector.board.microchip_mcp2221:
from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C

if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.microcontroller.fake_mcp2221.i2c import I2C as _I2C
else:
from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
self._i2c = _I2C(frequency=frequency)
return
if detector.board.greatfet_one:
Expand Down
10 changes: 8 additions & 2 deletions src/digitalio.py
Expand Up @@ -9,7 +9,7 @@
* Author(s): cefn
"""

import os
from adafruit_blinka.agnostic import board_id, detector

# pylint: disable=ungrouped-imports,wrong-import-position,unused-wildcard-import,wildcard-import
Expand Down Expand Up @@ -127,7 +127,13 @@
elif detector.board.greatfet_one:
from adafruit_blinka.microcontroller.nxp_lpc4330.pin import Pin
elif detector.board.microchip_mcp2221:
from adafruit_blinka.microcontroller.mcp2221.pin import Pin
if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.microcontroller.fake_mcp2221.pin import Pin
else:
from adafruit_blinka.microcontroller.mcp2221.pin import Pin
elif detector.chip.RP2040_U2IF:
from adafruit_blinka.microcontroller.rp2040_u2if.pin import Pin
# MicroPython Chips
Expand Down
10 changes: 8 additions & 2 deletions src/microcontroller/__init__.py
Expand Up @@ -7,7 +7,7 @@
* Author(s): Melissa LeBlanc-Williams
"""

import os
import sys
import time

Expand Down Expand Up @@ -123,7 +123,13 @@ def delay_us(delay):
elif chip_id == ap_chip.LPC4330:
from adafruit_blinka.microcontroller.nxp_lpc4330 import *
elif chip_id == ap_chip.MCP2221:
from adafruit_blinka.microcontroller.mcp2221 import *
if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.microcontroller.fake_mcp2221 import *
else:
from adafruit_blinka.microcontroller.mcp2221 import *
elif chip_id == ap_chip.MIPS24KC:
from adafruit_blinka.microcontroller.atheros.ar9331 import *
elif chip_id == ap_chip.MIPS24KEC:
Expand Down
10 changes: 8 additions & 2 deletions src/microcontroller/pin.py
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: MIT
"""Pins named after their chip name."""

import os
import sys
from adafruit_platformdetect.constants import chips as ap_chip, boards as ap_boards
from adafruit_blinka.agnostic import board_id, chip_id
Expand Down Expand Up @@ -97,7 +97,13 @@
elif chip_id == ap_chip.LPC4330:
from adafruit_blinka.microcontroller.nxp_lpc4330.pin import *
elif chip_id == ap_chip.MCP2221:
from adafruit_blinka.microcontroller.mcp2221.pin import *
if (
"BLINKA_FORCECHIP" in os.environ
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
):
from adafruit_blinka.microcontroller.fake_mcp2221.pin import *
else:
from adafruit_blinka.microcontroller.mcp2221.pin import *
elif chip_id == ap_chip.A10:
from adafruit_blinka.microcontroller.allwinner.a20.pin import *
elif chip_id == ap_chip.A20:
Expand Down

0 comments on commit 2e47afc

Please sign in to comment.