I am new to creating extensions. I would like to use the uBit.storage’s put and get to allow persistant storage for my students. I cannot pull cpp files from my github repository. I cannot create cpp files in the makecode ide. How do I add cpp files to an online extension so my students can use them? Thank you
This may not (or may) be a problem for your planned use: I think uBit.storage
is only persistent across power cycles and could be erased when the micro:bit is reprogrammed. (I think some code updates are just deltas and may not erase it? Someone from the MakeCode team may be able to provide some insight).
You may want to join the micro:bit Slack developer community, which has an extension developer’s channel. See: https://support.microbit.org/support/solutions/articles/19000016193-microbit-community-slack .
I mainly do extensions by:
- Follow the setup instructions at https://github.com/microsoft/pxt-microbit to create a developer setup.
- Clone an existing extension that is simple or close to what I want to do. I usually use one of the extensions I’ve created. For C++ stuff I copy: https://github.com/bsiever/microbit-pxt-i2cpins , which is a pretty minimal C++ project:
- Update the README.md
- Rename the .cpp and .ts files (i2crr.* for the above).
- Update the pxt.json with the new repo name, description, (author, feedback,) and the new file names.
- Change the code in the .cpp and corresponding .ts that calls it.
- Update test.ts to test the new features .
- Use the
pxt
command line to build and deploy it. - Repeat 3-5 as needed during development and debugging.
- Push to GitHub.
- Import into the live MakeCode editor and test.
I usually do the true local build without docker (export PXT_NODOCKER=1; pxt buildtarget --local
). It compiles faster than docker (and a lot faster than the default cloud build), but it’s not really well supported anymore and can be difficult to setup.
Hope that helps,
Bill
It is not a problem for uBit.storage to be persistent only across power cycles. Thank you for the micro:bit Slack developer community suggestion. I’ll have a look.
I found the reason for the the cpp files not being pulled. I added the shim.d.ts and now the extension loads as expected. I am now having a problem with some errors.
Here is the github repository: https://github.com/clausvalca226/flashstorage
Here is an example where I try to use it: https://makecode.microbit.org/_M2acsTLckVvy
I’m not sure if I should start a new thread now that the problem has changed.
Hi @mwest226,
I tried to create a fork and then “import” the fork (not add it as an extension, import the repo into MakeCode as a project). It didn’t work, which may mean there are still errors in the configuration. shim.d.ts
should be automatically generated for you by the compile process. (Notice the “Auto-generated” comment in this example)
I think the error may be partly due to the lack of actual typescript shims. Most extensions have both a .ts version of functions and a .cpp version. The .ts version is used in the simulator and to specify the API for TypeScript and the .cpp code is used in compiled/deployed projects.
I suspect you’ll need a .ts file in the project with something like:
//% color=#00FFFF
//% icon="\ue0b7"
//% block="Flash Storage"
namespace flashstorage {
//% blockId="getData" block="get data for %key|"
//% shim=flashstorage::getData
export function getData(key: string): string {
// Per https://github.com/microsoft/pxt-microbit/issues/4292
0;
// The above will do nothing in the simulator, but your application could actually use TypeScript map for simulation purposes.
}
}
The i2c project I mentioned earlier is a pretty minimal example: https://github.com/bsiever/microbit-pxt-i2cpins . The i2crr.cpp has a corresponding i2crr.ts that declares the API for TypeScript. This includes things like block names, hints, tool box names, toolbox color, etc. It also designates the C++ function that should be used when running on the device.
Would you happen to know a good tutorial that walks through creating the build environment on my Windows and creating your sample project. I am having trouble with the tutorials I have tried to follow.
Hey @mwest226 ,
I had some time over the past couple of days, so I created a prototype extension for get/put to flashstorage: https://github.com/bsiever/microbit-pxt-flashstorage .
I haven’t (yet) added support for anything other than storing and retrieving strings. Here’s a demo that actually stores a counter value by converting it to/from a string: https://makecode.microbit.org/_hiXaDp0aoAuF
- It’ll retrieve a stored counter when it starts.
- Button A increases the counter (but doesn’t update flash)
- Button A+B decreases the counters (but doesn’t update flash)
- Button B will update the flash with the current counter.
It also has some simulator support…but the simulator doesn’t really have flash so the refresh/reload resets all stored values. Still, if there is a store/put in one block and a retrieve/get in another, I think it’ll appear to work ok.
If a value isn’t in the storage the get()
returns an empty string, so string length can be checked to see if a get()
fails. It can use a lot more testing and a little cleanup. I think other functionality, like overloading for numeric types, can all be done just within the flashstorage.ts.
Hope that helps!
Hi @mwest226
Unfortunately, I don’t know of any good tutorials. Better support for potential extension authors seems to be a clear area of need (or opportunity).
Setting up the local build with Docker is described in the instructions in the pxt-microbit readme. The last time I tried it (more than a year ago), I thought Docker was a little clunky and preferred the no-Docker local build…but I don’t think no-Docker is well supported anymore. I’ve been continuing to use an older machine to avoid the pain of trying to set up a new environment.
There are a hodge-podge of resources that I’ve used, but none really addresses the local setup very well:
- SparkFun’s (older) tutorial: https://learn.sparkfun.com/tutorials/how-to-create-a-makecode-package-for-microbit/all
- The instructions on the pxt-microbit repo: https://github.com/microsoft/pxt-microbit
- Actual source for the CLI, which includes some details on the build engine options/settings: https://github.com/microsoft/pxt/tree/master/cli
- Peli’s video about extension authoring from within MakeCode: https://www.youtube.com/watch?v=ztrm4XehfGo
- Peli’s video about custom block creation: https://www.youtube.com/watch?v=Ku_nHstZS64
- AdaFruit’s tutorial (MakeCode, but not Micro:bit specific): https://learn.adafruit.com/custom-extensions-for-makecode?view=all
P.S. It looks like a CodeSpace may be an option for CODAL and MicroPython work: https://github.com/carlosperate/docker-microbit-toolchain . It’d be nice if there were something for micro:bit MakeCode too
This is awesome! Thank you for putting this together. I will have fun tinkering with it.
Thank you. I will take some time looking through these.
I see that the description of the get function (https://lancaster-university.github.io/microbit-docs/ubit/storage/) says “it is up to the user to free memory after use”. Does the PSTR function free up pair? Thank you
Thanks @mwest226 — Good catch! That was sloppy work and a memory leak. I’ve updated it, but I haven’t reviewed it any more to see if there are still problems or if there were problems elsewhere.
Would you be able to help me understand why you used PSTR? I believe it would be similar to using const in C, which would save the value in program space (flash) rather than ram. Thank you!
Hi @mwest226,
Well, in honesty it was a copy/paste. This was a prototype / proof of concept and I wasn’t submitting it for an official extension (although I’d be willing to do that if there’s interest). I was pretty lazy/sloppy and didn’t worry much about memory management. It may still be leaking memory. I’ll look into it a little more if time permits, but this is kind of a lot priority for me at the moment. Let me know if you dig in deeper and identify if it’s ok or has a flaw.
I knew that the MakeCode runtime uses memory managed string objects, so the char*
needs to be converted somehow. I don’t think I’ve done an extension that returns a string before, so I went looking for an example that would turn a char*
into MakeCode’s String
object. I’m pretty sure I just looked at the serial
read (here).
I find the micro:bit/CODAL+MakeCode strings a little confusing:
- CODAL has a
ManagedString
. I think these use reference counting. - MakeCode has
string
(TypeScript), aString
(C++), and aBoxedString
(C++). It looks like aString
is just aBoxedString*
(here). I think these allow the TypeScript code to do garbage collection. So…we need to end up with aString
(aka aBoxedString*
) for TypeScript.
I think it’s using this version of PSTR()
(here):
static inline String PSTR(ManagedString s) {
return mkString(s.toCharArray(), s.length());
}
So the ManagedString(const char *str)
constructor would be called. (ManagedString.h and ManagedString.cpp).
Then it goes to mkString()
, which delegates to mkStringCore()
. That does some nice things, like collecting empty strings into a single object. It looks like it sets up the MakeCode garbage collection and returns a BoxedString*
(aka a String
). I think the contents of the ManagedString
are copied to the allocated BoxedString
(like here).
Summary: Kind of a messy way to turn a char*
into MakeCode’s garbage collected string
.
By the way, I don’t think const
in C/C++ truly always ensures a value is stored in ROM/program memory/flash (but I haven’t looked at the C/C++ definitions to be sure). I think it merely is a guide to the compiler to prevent modification and may impact code optimization too, especially if it’s known to be static
or non-volatile
. An actual location probably depends on the compiler, target platform, optimizations, etc. On Arduino one has to use the PROGMEM
modifier on the declaration to ensure it’s placed in program memory (ROM). It’s possible to have the compiler generate the memory map and see where things are actually placed…at one point I did some experiments with the MakeCode toolchain, but I don’t remember the outcome (I had some other changes and it was no longer relevant to my work).
Bill
I understand that this was a prototype, though I really appreciate it. I think that there will be more than a few to benefit from this.
Your explanation makes a lot of sense. Thank you. I should have looked at the core first instead of googling PSTR.
You also make a good point about const behaviour being dependent on the compiler. I’m used to working with Microchip’s compiler in C. Thank you for your time and words of wisdom.