Examples

All code examples can be found in the examples directory of the repository.

Find all devices

Find and display all Free-Wili devices.

 1"""Example to find all Free-Wilis connected over USB."""
 2
 3import result
 4
 5from freewili import FreeWili
 6
 7# Find the first device and raise an exception otherwise
 8try:
 9    device = FreeWili.find_first().expect("Failed to find a FreeWili")
10except result.UnwrapError as ex:
11    print(ex)
12
13# Find all and display information about it.
14devices = FreeWili.find_all()
15print(f"Found {len(devices)} FreeWili(s)")
16for i, free_wili in enumerate(devices, start=1):
17    print(f"{i}. {free_wili}")
18    print(f"\t{free_wili.main}")
19    print(f"\t{free_wili.display}")
20    print(f"\t{free_wili.ftdi}")

Upload files

Upload files to the first Free-Wili device.

 1"""Upload a wasm file to a Free-Wili."""
 2
 3import pathlib
 4
 5from freewili import FreeWili
 6
 7# The fwi file to upload
 8my_fwi_file = pathlib.Path(r"~/path/to/MyFile.fwi")
 9# The wasm file to upload
10my_wasm_file = pathlib.Path(r"~/path/to/MyFile.wasm")
11
12# Find connected Free-Wilis
13devices = FreeWili.find_all()
14if not devices:
15    print("No Free-Wili devices found!")
16    exit(1)
17
18# Pick the first Free-Wili
19device = devices[0]
20
21# We can leave target_name and processor None and it will automatically
22# figure out where to send the file.
23device.send_file(my_fwi_file, None, None).expect("Failed to upload file")
24device.send_file(my_wasm_file, None, None).expect("Failed to upload file")
25device.run_script(my_wasm_file.name).expect("Failed to run script")

Toggle IO

Toggles IO on the first Free-Wili device.

 1"""Toggle IO on a Free-Wili."""
 2
 3from freewili import FreeWili
 4from freewili.types import IOMenuCommand
 5
 6# find a FreeWili device and open it
 7device = FreeWili.find_first().expect("Failed to find a FreeWili")
 8device.open().expect("Failed to open")
 9
10# Set IO 25 high
11print(device.set_io(25, IOMenuCommand.High).expect("Failed to set IO high"))
12# Set IO 25 Low
13print(device.set_io(25, IOMenuCommand.Low).expect("Failed to set IO low"))
14# Toggle IO 25 Low
15print(device.set_io(25, IOMenuCommand.Toggle).expect("Failed to toggle IO"))
16# PWM IO 25
17print(device.set_io(25, IOMenuCommand.Pwm, 10, 50).expect("Failed to toggle IO"))
18
19device.close()

Read Buttons

Read buttons on the first Free-Wili device.

 1"""Read buttons on a Free-Wili."""
 2
 3from freewili import FreeWili
 4
 5# find a FreeWili device and open it
 6device = FreeWili.find_first().expect("Failed to find a FreeWili")
 7device.open().expect("Failed to open")
 8
 9# Read the buttons and print on change
10print("Reading buttons...")
11last_button_read = device.read_all_buttons().expect("Failed to read buttons")
12
13keyboard_interrupt_requested = False
14while not keyboard_interrupt_requested:
15    try:
16        # Read the buttons
17        buttons = device.read_all_buttons().expect("Failed to read buttons")
18        for button_color, button_state in buttons.items():
19            # Check if the button state has changed
20            last_button_state = last_button_read[button_color]
21            if last_button_state == button_state:
22                continue
23            # Print the button change
24            msg = "Pressed \N{WHITE HEAVY CHECK MARK}"
25            if button_state == 0:
26                msg = "Released \N{CROSS MARK}"
27            print(f"{button_color.name} {msg}")
28        # Save the button state for the next loop
29        last_button_read = buttons
30    except KeyboardInterrupt:
31        keyboard_interrupt_requested = True
32
33device.close()

Set Board LEDs

Set Board LEDs on the first Free-Wili device.

 1"""Set Board RGB on a Free-Wili."""
 2
 3import time
 4
 5from freewili import FreeWili
 6
 7# find a FreeWili device and open it
 8device = FreeWili.find_first().expect("Failed to find a FreeWili")
 9device.open().expect("Failed to open")
10
11# Turn the LEDs on
12for led_num in range(7):
13    print(device.set_board_leds(led_num, 10, 10, led_num * 2).expect("Failed to set LED"))
14# Wait so we can see them
15time.sleep(3)
16# Turn the LEDS off
17for led_num in reversed(range(7)):
18    print(device.set_board_leds(led_num, 0, 0, 0).expect("Failed to set LED"))
19
20device.close()

SparkFun 9DoF IMU Breakout - ISM330DHCX, MMC5983MA (Qwiic)

SparkFun 9DoF IMU Breakout example over I2C.

  1"""Example I2C on a FreeWili with SparkFun 9DoF IMU Breakout - ISM330DHCX, MMC5983MA (Qwiic) attached.
  2
  3https://www.sparkfun.com/sparkfun-9dof-imu-breakout-ism330dhcx-mmc5983ma-qwiic.html
  4ISM330DHCX I2C Address: 0x6B (Default)
  5MMC5983MA Magnetometer I2C Address: 0x30
  6"""
  7
  8import enum
  9
 10from result import Err, Ok
 11
 12from freewili import FreeWili
 13
 14MMC5983MA_ADDR = 0x30
 15ISM330DHCX_ADDR = 0x6B
 16
 17
 18class MMC5983MA(enum.Enum):
 19    """Register list for MMC5983MA Magnetometer."""
 20
 21    Xout0 = 0x00  # Xout [17:10]
 22    Xout1 = 0x01  # Xout [9:2]
 23    Yout0 = 0x02  # Yout [17:10]
 24    Yout1 = 0x03  # Yout [9:2]
 25    Zout0 = 0x04  # Zout [17:10]
 26    Zout1 = 0x05  # Zout [9:2]
 27    XYZout2 = 0x06  # Xout[1:0], Yout[1:0], Zout[1:0]
 28    Tout = 0x07  # Temperature output
 29    Status = 0x08  # Device status
 30    Control0 = 0x09  # Control register 0
 31    Control1 = 0x0A  # Control register 1
 32    Control2 = 0x0B  # Control register 2
 33    Control3 = 0x0C  # Control register 3
 34    ProductID = 0x2F  # Product ID
 35
 36
 37class ISM330DHCX(enum.Enum):
 38    """Register list for ISM330DHCX."""
 39
 40    FUNC_CFG_ACCESS = 0x01
 41    PIN_CTRL = 0x02
 42    FIFO_CTRL1 = 0x07
 43    FIFO_CTRL2 = 0x08
 44    FIFO_CTRL3 = 0x09
 45    FIFO_CTRL4 = 0x0A
 46    COUNTER_BDR_REG1 = 0x0B
 47    COUNTER_BDR_REG2 = 0x0C
 48    INT1_CTRL = 0x0D
 49    INT2_CTRL = 0x0E
 50    WHO_AM_I = 0x0F
 51    CTRL1_XL = 0x10
 52    CTRL2_G = 0x11
 53    CTRL3_C = 0x12
 54    CTRL4_C = 0x13
 55    CTRL5_C = 0x14
 56    CTRL6_C = 0x15
 57    CTRL7_G = 0x16
 58    CTRL8_XL = 0x17
 59    CTRL9_XL = 0x18
 60    CTRL10_C = 0x19
 61    ALL_INT_SRC = 0x1
 62    WAKE_UP_SRC = 0x1B
 63    TAP_SRC = 0x1C
 64    DRD_SRC = 0x1D
 65    STATUS_REG = 0x1E
 66    STATUS_SPIAux = 0x1E
 67    OUT_TEMP_L = 0x20
 68    OUT_TEMP_H = 0x21
 69    OUTX_L_G = 0x22
 70    OUTX_H_G = 0x23
 71    OUTY_L_G = 0x24
 72    OUTY_H_G = 0x25
 73    OUTZ_L_G = 0x26
 74    OUTZ_H_G = 0x27
 75    OUTX_L_A = 0x28
 76    OUTX_H_A = 0x29
 77    OUTY_L_A = 0x2A
 78    OUTY_H_A = 0x2B
 79    OUTZ_L_A = 0x2C
 80    OUTZ_H_A = 0x2D
 81    EMB_FUNC_STATUS_MAINPAGE = 0x35
 82    FSM_STATUS_A_MAINPAGE = 0x36
 83    FSM_STATUS_B_MAINPAGE = 0x37
 84    MLC_STATUS_MAINPAGE = 0x38
 85    STATUS_MASTER_MAINPAGE = 0x39
 86    FIFO_STATUS1 = 0x3A
 87    FIFO_STATUS2 = 0x3B
 88    TIMESTAMP0 = 0x40
 89    TIMESTAMP1 = 0x41
 90    TIMESTAMP2 = 0x42
 91    TIMESTAMP3 = 0x43
 92    TAP_CFG0 = 0x56
 93    TAP_CFG1 = 0x57
 94    TAP_CFG2 = 0x58
 95    TAP_THS_6D = 0x59
 96    INT_DUR2 = 0x5A
 97    WAKE_UP_THS = 0x5B
 98    WAKE_UP_DUR = 0x5C
 99    FREE_FALL = 0x5D
100    MD1_CFG = 0x5E
101    MD2_CFG = 0x5F
102    INTERNAL_FREQ_FINE = 0x63
103    INT_OIS = 0x6F
104    CTRL1_OIS = 0x70
105    CTRL2_OIS = 0x71
106    CTRL3_OIS = 0x72
107    X_OFS_USR = 0x73
108    Y_OFS_USR = 0x74
109    Z_OFS_USR = 0x75
110    FIFO_DATA_OUT_TAG = 0x78
111    FIFO_DATA_OUT_X_L = 0x79
112    FIFO_DATA_OUT_X_H = 0x7A
113    FIFO_DATA_OUT_Y_L = 0x7B
114    FIFO_DATA_OUT_Y_H = 0x7C
115    FIFO_DATA_OUT_Z_L = 0x7D
116    FIFO_DATA_OUT_Z_H = 0x7E
117
118
119def get_mmc5983ma_temperature(device: FreeWili) -> tuple[float, int]:
120    """Get temperature on MMC5983MA.
121
122    Arguments:
123    ----------
124        device: FreeWili
125            FreeWili device to use.
126
127    Returns:
128    --------
129        tuple[float, int]:
130            (Temperature in degrees Celcius, timestamp in ns).
131    """
132    resp = device.write_i2c(MMC5983MA_ADDR, MMC5983MA.Control0.value, bytes([0x2A])).expect("Enable temp measure")
133    # print(resp.is_ok())
134    # print("Waiting for temperature measurement...")
135    while True:
136        resp = device.read_i2c(MMC5983MA_ADDR, MMC5983MA.Status.value, 1).expect("Reading Status failed")
137        status = resp.response_as_bytes().expect("Status bytes")[0]
138        if (status & 0x2) == 0x2:
139            # print("Temperature measurement done!")
140            break
141    resp = device.read_i2c(MMC5983MA_ADDR, MMC5983MA.Tout.value, 1).expect("Reading Tout failed")
142    # Temperature output, unsigned format. The range is -75~125°C, about 0.8°C/LSB, 00000000 stands for -75°C
143    temp = resp.response_as_bytes().expect("MMC5983MA.Tout")
144    temp_int = int.from_bytes(temp, byteorder="little", signed=False)
145    converted = temp_int * 0.8 - 75
146    # print(resp._raw.strip())
147    return (converted, resp.timestamp)
148
149
150def get_mmc5983ma_magnetic_sensor(device: FreeWili) -> tuple[tuple[int, int, int], int]:
151    """Get magnetic field data on MMC5983MA.
152
153    Arguments:
154    ----------
155        device: FreeWili
156            FreeWili device to use.
157
158    Returns:
159    --------
160        tuple[tuple[int, int, int], int]:
161            ((x, y, z), timestamp in ns).
162    """
163    resp = device.write_i2c(MMC5983MA_ADDR, MMC5983MA.Control0.value, bytes([0x29])).expect("Enable magnetic field")
164    # print(resp.is_ok())
165    # print("Waiting for temperature measurement...")
166    while True:
167        resp = device.read_i2c(MMC5983MA_ADDR, MMC5983MA.Status.value, 1).expect("Reading Status failed")
168        status = resp.response_as_bytes().expect("Status bytes")[0]
169        if (status & 0x1) == 0x1:
170            # print("Temperature measurement done!")
171            break
172    resp = device.read_i2c(MMC5983MA_ADDR, MMC5983MA.Xout0.value, 6).expect("Reading Tout failed")
173    data = resp.response_as_bytes().expect("MMC5983MA.Xout0")
174    x = int.from_bytes(data[0:2], byteorder="little", signed=False) << 2
175    y = int.from_bytes(data[2:4], byteorder="little", signed=False) << 2
176    z = int.from_bytes(data[4:6], byteorder="little", signed=False) << 2
177    # print(resp._raw.strip())
178    return ((x, y, z), resp.timestamp)
179
180
181# find a FreeWili device
182match FreeWili.find_first():
183    case Ok(d):
184        device = d
185        device.stay_open = True
186        print(f"Using {device}")
187    case Err(msg):
188        print(msg)
189        exit(1)
190
191try:
192    # Poll the I2C to make sure we can read the breakout board
193    print("Polling I2C...")
194    resp = device.poll_i2c().expect("Failed to poll i2c")
195    addresses = resp.response_as_bytes().expect("Failed to get response bytes")
196    if addresses != bytes([2, MMC5983MA_ADDR, ISM330DHCX_ADDR]):
197        print(f"Expected addresses on I2C are incorrect, got {list(addresses)}!")
198        exit(1)
199
200    first_ts = resp.timestamp
201    print(resp.timestamp_as_datetime().expect("Failed to convert to datetime"))
202    while True:
203        try:
204            temp_c, ts = get_mmc5983ma_temperature(device)
205            temp_f = temp_c * 1.8 + 32
206            print(f"[{ts - first_ts}] Temperature: {temp_c:.2f}C ({temp_f:.2f}F)")
207            magnetic_data, ts = get_mmc5983ma_magnetic_sensor(device)
208            print(f"[{ts - first_ts}] Magnetic Field: {magnetic_data}")
209        except KeyboardInterrupt:
210            break
211finally:
212    device.close()
213
214print("Done.")