wokwi-features icon indicating copy to clipboard operation
wokwi-features copied to clipboard

Create new parts (chips, sensors, etc.) with custom logic

Open urish opened this issue 3 years ago • 36 comments
trafficstars

Make it possible to create custom parts and program your own logic:

  1. Define the pins for the part (e.g., for an I2C sensor: GND, VCC, SCL, SDA, INT)
  2. Write some code to implement the logic for the part
  3. Load this part into Wokwi and use it in the simulation.

I've done some prototyping, and one way to implement this in a secure and performant way is to use AssemblyScript together with Web Assembly.

Initial thoughts about the API for creating custom parts:

  1. Keep the function names similar to Arduino (e.g. digitalRead/digitalWrite/pinMode)
  2. Make it easy to include standard protocols (such as UART, I2C, SPI)
  3. The first version should focus in digital simulation, as the Analog part of the simulator is not very mature at this time.

Here's a proposal of what the code for a simple part (pulse counter with an I2C interface) might look like:

import { createI2CDevice, digitalWatch, I2CDevice, I2CPins, registerChip } from 'wokwi-api';

export enum Pins {
  GND,
  VCC,
  SCL,
  SDA,
  PULSE,
}

enum Events {
  PulseIn,
}

const ADDRESS: u8 = 0x22;

export class CounterChip implements I2CDevice {
  private counter: u32;
  private byteIndex: u8;

  constructor() {
    this.counter = 0;
    this.byteIndex = 0;
    createI2CDevice(this, new I2CPins(Pins.SCL, Pins.SDA), ADDRESS);
    digitalWatch(Pins.PULSE, Events.PulseIn);
  }

  i2cConnect(): boolean {
    this.byteIndex = 0;
    return true; /* ack */
  }

  i2cReadByte(): u8 {
    const shiftAmount = this.byteIndex++ * 8;
    return u8(this.counter >> shiftAmount);
  }

  i2cWriteByte(value: u8): void {
    // Writing any value just resets the counter
    this.counter = 0;
  }

  i2cDisconnect(): void {
    // do nothing
  }

  onEvent(event: i32, data: i32): void {
    switch (event) {
      case Events.PulseIn:
        /* data holds the new pin value: 1 for rising edge */
        if (data) {
          this.counter++;
        }
        break;
    }
  }
}

registerChip('i2c-counter', CounterChip);

And another example - HC-SR04 Ultrasonic sensor (for now, with a fixed distance):

import { addClockEvent, digitalWatch, digitalWrite, HIGH, LOW, OUTPUT, pinMode } from './wokwi-api';

const distance = 300;

enum Pins {
  VCC,
  GND,
  ECHO,
  TRIG,
}

enum Events {
  TrigChanged,
  StartEcho,
  EndEcho,
}

export class UltrasonicSensor {
  constructor() {
    digitalWatch(Pins.TRIG, Events.TrigChanged);
    pinMode(Pins.ECHO, OUTPUT);
    digitalWrite(Pins.ECHO, LOW);
  }

  onTrigChanged(value: boolean): void {
    if (!value) {
      const us = 1000;
      const echoDelay = 300 * us;
      const echoTime = Math.round(distance * 58.82 * us);
      addClockEvent(echoDelay, Events.StartEcho);
      addClockEvent(echoDelay + echoTime, Events.EndEcho);
    }
  }

  onEvent(event: i32, data: i32): void {
    switch (event) {
      case Events.TrigChanged:
        this.onTrigChanged(bool(data));
        break;

      case Events.StartEcho:
        digitalWrite(Pins.ECHO, HIGH);
        break;

      case Events.EndEcho:
        digitalWrite(Pins.ECHO, LOW);
        break;
    }
  }
}

urish avatar Feb 03 '22 11:02 urish

Yes please! ❤️

kartben avatar Feb 03 '22 11:02 kartben

Started working on this and uploaded an early prototype so users can start playing around and share their feedback.

Here's a quick demo project: https://wokwi.com/projects/327144279206003284 Press "F1" and select "Create a custom C chip (alpha)", then run the simulation to see the Arduino sketch communicating with the custom I2C chip. The chip logic is defined in "i2c-counter.chip.c", and the pinout in "i2c-counter.chip.json".

And a google doc with further explanations: https://link.wokwi.com/custom-chips-alpha

urish avatar Mar 26 '22 23:03 urish

Can I suggest the new part creating uses the Fritzing images and pin maps to speed up device creation?

sjamesparsonsjr avatar Apr 06 '22 17:04 sjamesparsonsjr

@sjamesparsonsjr that suggestion may fit better in #302

urish avatar Apr 09 '22 18:04 urish

Hi, This is great. I have successfully created a simple chip based on the i2c-counter example. Is it possible to create more than one chip for each system model? Can a created chip be 'saved' to be used for other simulations?
I hope the development continues!

Project487 avatar Jul 01 '22 03:07 Project487

Thanks for the feedback!

It's possible to create multiple instance of each chip type. Here's a recent example with 2 copies of the same chip:

https://wokwi.com/projects/335750100024296020

What do you mean by "saving" custom chips for using in other simulation?

urish avatar Jul 02 '22 11:07 urish

Hi, Thanks for the reply. The example given shows the chip defined as "chip-bounce"; where is this definition made? Can "chip-bounce" be saved as an entity to be used later, much like the the 'new parts' list on the simulation panel? Diagram.json shows some interesting parts not shown in the 'new parts' drop down. Is there a list of these parts? (I came across an example using the Adafruit SSD1306 OLED display, wokwi-ssd1306, also not listed in the 'add new part' drop-down menu). I would really like to use the chip creation feature and hope these questions aren't too naive. Thanks again.

Project487 avatar Jul 03 '22 21:07 Project487

The example given shows the chip defined as "chip-bounce"; where is this definition made? Can "chip-bounce" be saved as an entity to be used later, much like the the 'new parts' list on the simulation panel?

The definition is implicitly made whenever you have a pair of "whatever.chip.json" and "whatever.chip.c" files. Right now, the chips are saved along with the project, but we're looking into a way to make them separate entities that can be imported into a project (much like you can import Arduino libraries using the Library Manager).

The current solution we're looking into is hosting custom chips on GitHub - you create a github repo with the custom chip source code and definition, and then you'll be able to submit the repo to a central Wokwi Chip registry, and users will be able to pull chips from this registry. Still working out the details.

Diagram.json shows some interesting parts not shown in the 'new parts' drop down. Is there a list of these parts? (I came across an example using the Adafruit SSD1306 OLED display, wokwi-ssd1306, also not listed in the 'add new part' drop-down menu).

These parts aren't officially supported. Some are incomplete (e.g. wokwi-serial-port - see #149), or deprecated (like wokwi-ssd1306), and some just need some documentation and perhaps a bit of refactoring (e.g. #240).

I'm curious, what are you using the custom chips for?

urish avatar Jul 07 '22 09:07 urish

Thanks for the information. A GitHub chip repository seems very reasonable. I will await developments. The chips are sensors for a project (a model submarine!) I want to build; the sensors need to interact with one-another. For example a sensor determining the water level in ballast tanks needs to affect the output of (say) an MPU6050 accelerometer so feedback can adjust pitch (level) of the sub. Currently I think the outputs have to be provided independently with sliders. Is the code available for the officially supported chips?
Thanks again.

Project487 avatar Jul 07 '22 23:07 Project487

The chips are sensors for a project (a model submarine!) I want to build

Sounds like a cool use-case! Do you have some models?

Is the code available for the officially supported chips?

Only for a few of them, e.g. the ILI9163 Display Driver. I guess you are looking for the code of the MPU6050? Is there anything else?

urish avatar Jul 24 '22 12:07 urish

Not sure if this is the appropriate place to put this, but I was thinking that it would be cool to be able to select several predefined components and click a button that allowed you to make your own custom component. So , for example, If I m working with a lot of LEDs and their associated resistors, I would like to be able to generate an LED and connect it to a resistor, then with both items selected, define a custom component that would only show up locally in my dev. environment.

Then every time I needed one of these, I could grab it from my + button under My Custom Components and voila it would appear just how I had wired it. This would be super easy to code and the combined elements as their own custom component would have all of the attributes that were not already defined. In other words, it would have two pins (the two open pins) to connect to as well as the resistance on the resistor, the color on the LED. When I generate my custom component made of other components, that stuff would automatically be exposed. Maybe that's a different request, but just in case.

jaseinatl avatar Sep 21 '22 21:09 jaseinatl

Maybe that's a different request, but just in case.

Yeah, that sounds like a new feature request - some kind of "modules" library. One way to sort-of achieve this now is to have a project with your common "modules", and then you can select several parts, copy them, and paste them into another projects. They'll be copied along with all the internal connections. Anyway, feel free to open a new feature request!

urish avatar Sep 21 '22 22:09 urish

Update: the Custom Chip API is now getting into a beta phase. There will probably be some minor changes, but I think we're already clear on the general direction.

You can view the current API reference here: https://gist.github.com/urish/f9129d3d34ffd557eccf354907663051, and we expect to shortly migrate it to https://docs.wokwi.com.

Here's a bunch of examples for custom chips, showing what you can do with the current API:

urish avatar Sep 28 '22 20:09 urish

Nice work!

The API documentation is clear, but it lacks information about the chip.json structure (display, controls). BTW: in doc is analog example, but not here.

And my propositions:

  • It should be possible to define the appearance of the element. For example:
    • by handling wokwi-elements format,
    • selecting an case (e.g .: DIP_n_, SOP_n_, TQFP_n_, TO-98, TO-225, TO-220),
    • uploading an SVG file,
  • Are you planning to create a custom-element library?

//edit:

You wrote:

It's possible to create multiple instance of each chip type. Here's a recent example with 2 copies of the same chip:

Is possibl eto create multiple different chips? (eg XOR CD4030 + NAND MC14093B )

bato3 avatar Oct 08 '22 00:10 bato3

Thanks for the feedback @bato3!

It should be possible to define the appearance of the element. For example:

Yeah, the details aren't clear yet, but this might be part of #302. Probably uploading an SVG file and defining the pins.

Are you planning to create a custom-element library?

There'll probably be some way to submit your custom chips and for other users to add them. Perhaps through GitHub. Still thinking of possible ways to accomplish this.

Is possibl eto create multiple different chips?

Yes, you can have many chip types in a single project, and multiple instances of each chip type.

urish avatar Oct 08 '22 13:10 urish

Are you planning to create a custom SVG element resource that WOKWI loads and all SVGS can simply reference? Like what you do with the "hole" symbol on your current SVG artwork?

Ideally, given a default library set, someone could create any svg and include your resources for "pins" or solder points or connectors of any sort and that SVG would be ready to be added to the layout, including accessibility to connections. The only thing it would require for simulation would be the underlying code which would benefit from the standardization of the connector SVG resources.

By standardizing every connector type and perhaps some common display types like (on board LEDs), simple hooks in the API would help with the logic part. But even before the logic part was not done, having the SVG with standardized components would enable layout and connections immediately. Upon adding a custom component all of the "pin" SVG symbols would be enabled for connections, for example. This might make it easier to debug upon running the simulation. Ill check out 302 to see if its covered there. Great work on custom elements. thanks

jaseinatl avatar Oct 08 '22 14:10 jaseinatl

Probably for starters, the user will just provide the complete SVG. To make things simple. Then we'll see how to evolve it based on how users will use it and the feedback we get (that's how Wokwi goes in general)

urish avatar Oct 09 '22 20:10 urish

Update: We have a proof-of-concept of creating custom chips using the Rust language. Here's an example of an inverter:

https://wokwi.com/projects/346597452510397012

urish avatar Nov 22 '22 13:11 urish

New docs for custom chips: https://docs.wokwi.com/chips-api/getting-started

Also, a new example of a chip hosted in GitHub repo: https://github.com/wokwi/inverter-chip

urish avatar Dec 06 '22 12:12 urish

Thank you for the progress on this amazing addition, Can I confirm that the custom chip functionality isn't currently supported in Visual Studio? (or do i need to put the chip definitions somewhere other than root)

alextrical avatar Feb 12 '23 18:02 alextrical

Can I confirm that the custom chip functionality isn't currently supported in Visual Studio?

It is supported in Visual Studio Code. Please take a look at the documentation: https://docs.wokwi.com/vscode/project-config#custom-chips

Is the documentation about this clear or does it need any improvements?

urish avatar Feb 12 '23 18:02 urish

Ah, perfect, it seems that once again I failed to locate the relevant documentation.

It took me a second to work out that its possible to replace the 'wasm' with the 'c' file, and now it works perfectly. I think the thing that tripped me up was the requirement to define the chip in the '.toml' file, instead of the web version auto detecting, though its added ability to add the chip definitions to sub folders is really neat.

Keep up the amazing work

alextrical avatar Feb 12 '23 18:02 alextrical

I may have spoke too soon on it working with a *.chip.c file, it seems to hang on the 'Loading project...' message. I will convert the chips over to a wasm and load them instead :)

alextrical avatar Feb 12 '23 19:02 alextrical

Yeah, it doesn't know how to compile things - you have to feed it with binaries :)

Do you need any assistance in converting the chips to wasm?

urish avatar Feb 12 '23 19:02 urish

I will see what I can do for a little bit, using the existing examples, and try to convert the 'eeprom_custom_chip_test' example into wasm.

I will let you know in an hour if i'm stuck. :)

alextrical avatar Feb 12 '23 19:02 alextrical

Ive had some luck using your example for an inverter and the EEPROM example, to compile the wasm at the following repo https://github.com/alextrical/wokwi-24C01-custom-chip Oddly i had issues getting the Build part of the Workflow to trigger ("github.event_name == 'push'" wasn't triggering when pushing from GitHub Desktop) and then the "ncipollo/release-action" failed with the following error 'Error undefined: No tag found in ref or input!'

Ive managed to force it through to a release, and can now see the desired chip.zip file :)

edit: all fixed, I wasn't using "tags" in the push, now I have done that it works without having to edit the Workflow. The error was pretty clear

alextrical avatar Feb 12 '23 20:02 alextrical

New UI to easily create custom chips and add them to your project:

image

image

Also, updated the documentation:

urish avatar Jul 28 '23 07:07 urish

New video tutorial - how to create custom chips, 3 examples in 15 minutes

https://youtu.be/yzdCS3A4DvU

urish avatar Aug 12 '23 08:08 urish

This is really great! One question, is or will there be a searchable part library, where i can checkout what other users did? Just so I don't have to reinvent the wheel when it comes to common chips.

InRiPa avatar Nov 14 '23 06:11 InRiPa