tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.25k stars 900 forks source link

Embrace run-time determination of target characteristics in a standard way #2326

Open rayozzie opened 2 years ago

rayozzie commented 2 years ago

We - Blues Wireless - make a cellular peripheral that connects with host MCU's ranging from 8-bit MCUs and the 16-bit MSP430, all the way up to Raspberry Pi's. Our developer audience is split roughly in half between RPi-class and microcontroller-class, and the microcontrollers are hugely fragmented.

Developer experience means a lot to us: dev.blues.io

As such, we have implemented the moral equivalent of a "user agent" within the libraries that the developer uses to talk with our Notecard, and we use that info to try to make our developer tools and Examples better based on trends of which Microcontrollers are used more than others.

In full golang, we do this - courtesy of the great shirou/gopsutil package: https://github.com/blues/note-go/blob/main/notecard/ua.go

In tinygo, I was limited to doing this: https://github.com/blues/note-tinygo/blob/master/ua.go

I have several comments.

1) I was pretty surprised that runtime.Version() isn't implemented. You might consider implementing this.

2) I would like to propose a very simple feature that will take about 30m of editing, wherein a standard feature is implemented across all target .go's such as this: https://github.com/tinygo-org/tinygo/blob/release/src/machine/board_arduino_nano33.go In these GO files, you would implement these two strings - both required in all machine implementations:

// Target identifiers const ( target_DISPLAY = "Arduino NANO 33 IoT" target_ID = "arduino-nano33" )

These would ultimately prove to be very helpful not just for analytics, but also in case the developer needs to do conditional code based on specific oddball characteristics of a specific MCU.

3) It would be great if there were a standard set of methods implemented by all platforms, analogous to the gopsutil functions. I say this because as more and more people do implement reusable library functions, they will want to likely do conditional code based upon machine capabilities. You might even consider having standard "UART interface enumerators" and "I2C interface enumerators", and so on. It would be truly great if the golang dev (and thus ua.go) could get "target name" in a standard way across targets, by defining standard const's for things like "nucleo-l432kc" and "STMicroelectronics Nucleo L432KC", because I think people might want to do run-time checks as well as analytics.

kenbell commented 2 years ago

TinyGo supports build-time strings the same syntax as regular Go: https://github.com/tinygo-org/tinygo/blob/release/main.go#L1094

Could perhaps extend this to inject the 'target name' into a known string variable during build?

aykevl commented 2 years ago

Thank you for your interest! These are all good ideas.

In tinygo, I was limited to doing this: https://github.com/blues/note-tinygo/blob/master/ua.go

Hmm, note that runtime.GOOS/runtime.GOARCH are mostly fake when targeting MCUs. They all just say linux/arm but that's because we have to pick something to be compatible with the Go standard library.

  1. I was pretty surprised that runtime.Version() isn't implemented. You might consider implementing this.

Fair enough. Shouldn't be very difficult. It's one of those many things that need to be done... (If anyone wants to do it: I think the easiest way is to write only the declaration, not the definition of runtime.Version and implement it a bit like how syscall.Syscall etc is implemented: by generating code inline).

  1. I would like to propose a very simple feature that will take about 30m of editing, wherein a standard feature is implemented across all target .go's such as this: https://github.com/tinygo-org/tinygo/blob/release/src/machine/board_arduino_nano33.go In these GO files, you would implement these two strings - both required in all machine implementations:

This generally seems like a useful thing to me. I'm a little bit worried that people are going to (ab)use this instead of build tags, but that's a risk for any new feature.

You can already read the MCU name if you know the MCU family name. For example, if you know the device is one of the Atmel SAM devices you can get the chip name like this:

// +build atsamd21 atsamd51

package main // or whatever

import "device/sam"

func main() {
    println("device:", sam.Device)
    println("cpu:   ", sam.CPU)
}

This should print something like this:

device: ATSAMD51J19A
cpu:    CM4

3. It would be great if there were a standard set of methods implemented by all platforms, analogous to the gopsutil functions. I say this because as more and more people do implement reusable library functions, they will want to likely do conditional code based upon machine capabilities. You might even consider having standard "UART interface enumerators" and "I2C interface enumerators", and so on.

I've thought about exactly this, but I'm not entirely sure how to best support this. The problem is that such peripherals are not interchangeable on most MCUs (the exception is the nrf series, where they are interchangeable). Usually, a UART only supports a limited number of pins, or is even hardwired to specific pins. And remember that which pins are usable also depend on the board: you can't just say "start SPI and write these bytes": you have to configure which pins to use somewhere.

The best way I've solved this so far involves build tags. For example, a personal project of mine might use one file that looks like this:

// +build feather_stm32f405

package main

import "machine"

const (
    LED_PIN           = machine.A0
    LED_PIN2          = machine.A1
    BUTTON_SPEED      = machine.D5
    BUTTON_SPREAD     = machine.D6
    BUTTON_PALETTE    = machine.D9
    BUTTON_BRIGHTNESS = machine.D10
)

and another file that looks like this:

// +build esp32

package main

const (
    LED_PIN           = 13
    LED_PIN2          = 33
    BUTTON_SPEED      = 12
    BUTTON_SPREAD     = 14
    BUTTON_PALETTE    = 27
    BUTTON_BRIGHTNESS = 26
)

This way, tinygo flash works for both boards.

It would be truly great if the golang dev (and thus ua.go) could get "target name" in a standard way across targets, by defining standard const's for things like "nucleo-l432kc" and "STMicroelectronics Nucleo L432KC", because I think people might want to do run-time checks as well as analytics.

"Target" is somewhat of an overloaded term. There is the board ID as used in TinyGo with an associated build tag (that's usually the same string but with - replaced by _), there is the board name that we don't really store anywhere except in the README, and there is the chip name that can be accessed through the device packages as I described above. Adding support for the chip name seems fine by me. Adding support for the board name is definitely possible but a bit more work, especially to maintain it going forward.

rayozzie commented 2 years ago

Thx. Unless I'm misunderstanding, it seems as though build tags are a great (arguably the best) way to statically conditionalize if you know your intended board.

The "ua" thing needs the inverse, though, which is "given all potential boards, which one am i running on and what are the characteristics"?

aykevl commented 2 years ago

Here is part of the solution: https://github.com/tinygo-org/tinygo/pull/2332 It only includes the device (chip) name for now, because that's easy to support. I think that already provides most of the solution: based on the chip name, you can infer other details like amount of available RAM and CPU name. (But I realize it's not a complete solution, just a starting point).

rayozzie commented 2 years ago

Oh this is a very big improvement. Thank you.

deadprogram commented 2 years ago

I realize I probably should not have marked this "next release" since what we have implemented so far is only a partial solution. So I will leave this open, but remove that tag.

rayozzie commented 2 years ago

Hey Ron, will you be at iot all stars?

We can coordinate to meet then if so.

If not, let me know and we’ll figure something out.

From: Ron Evans @.> Reply-To: tinygo-org/tinygo @.> Date: Wednesday, January 26, 2022 at 7:06 PM To: tinygo-org/tinygo @.> Cc: Ray Ozzie @.>, Author @.***> Subject: Re: [tinygo-org/tinygo] Embrace run-time determination of target characteristics in a standard way (Issue #2326)

I realize I probably should not have marked this "next release" since what we have implemented so far is only a partial solution. So I will leave this open, but remove that tag.

— Reply to this email directly, view it on GitHubhttps://github.com/tinygo-org/tinygo/issues/2326#issuecomment-1022456358, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAF2CPP4FVZ5V2DZWYRW6CTUYAZ2JANCNFSM5I43CCDQ. You are receiving this because you authored the thread.Message ID: @.***>

deadprogram commented 2 years ago

HI @rayozzie yes, I will be there. I will send you DM to make suitable arrangements. Thanks!