PlatformIO is not Visual Studio based.
It can use VSCode (a different, cross-platform, thing) as the IDE. It can use many other things too. Eclipse, for example. Or Atom.
It does debugging using JTAG, gdb and a GUI.
oh ? i saw in that video he was installing visual studio code and then installing platformio plugin. so i thought it was visual studio based.
i need to look into those things. i'm getting out of touch with what is out there.
I was just trying to help someone out with a proof of concept based on an arduino cause that is what they had laying around ( student in india... ).
This microscheduler is something i have used many many times but written in PL/M on 8051 or Basic on various other processors ( Mikroe basic for pic, avr , arm , Bascom avr , oshonsoft basic, swordfish basic for pic f18 , B4R , Great Cow Basic , Annex on ESP32 and ESP8266
Porting it to Arduino C proved to be a painful learning curve. First because of the C compiler idiosyncrasies (tinkercad can't compile it at all , Arduino IDE compiles without error/warning but the binary doesn't work (i initially did not have an arduino around so i was banking on the simulators, this afternoon i went out and bought a board to try it on) , Wokwi finally let me trace it using GDB ) and second because of the bad simulators. I'm not a c wizard. i can read it , but writing it and knowing all the intimate details is not for me. (like knowing how to create a function pointer and then store that in a struct. A function pointer is nothing but an address , which in this case is a 16 bit number so it can be stored in an u_int16. i first attempted to simply store that as an integer but that didn't work. C deos't work that way.
in PL/M anything is passed by reference . whether variable or function.
if can do
Procedure Createdaemon (word interval , word *function_to_be _called) // the * signifies what follows is not a variable but a function so it stores addressof
table (1,1) = interval
table(1,2) = function_to_be_called
end procedure
...
call table(1,2) : calls the stored address
of course call table (1,1) would crash the program as that is a regular value. basically the 'call operator' moves the value stored at (1,1) onto the instruction pointer. if you put arguments , it performs push and pop operations on the stack
result = call table(1,2)(some_argument, some_other_argument)
compiles to
push some_other_argument
push some_argument
push ip+4 ' push return address
mov ip @table(1,2) ' move content of table 1,2 to instruction pointer
pop result;
the code of the function is
[code]
pop return_address
pop arg1
pop arg2
..... do what needs doing
push result
mov ip return_address
as simple as can be.
It irritates me that a platform that is so popular is in such a poor state and so difficult to get started with. A little bit from here, a bit from there , futz it together , drop some more gobbledegook from somewhere else. I'm used to tools that just work. Launch setup and start coding. No need to puzzle it together.
Anyway, got it running, student understand the logic of a scheduler.
No more delay and sleep operations that block the CPU. you can create little tasks , set an interval and start/stop/pause/resume them and the tasks can stop themselves and react to emergency signals. that was the goal. non concurrent , cooperative multitasking micro threads on small microcontrollers.
The task was to write a small monitor for a water boiler.
if the boiler is on : blink an led at 1 second interval and count up two counters (one lifetime run time , one current run time)
display lifetime and current runtime on lcd
also display temperature (read from analog input)
so we have a simple function that , upon calling , toggles an i/o and increments 2 counters.
in the main program we simply control the runstate of that routine. the hardware timer does the rest.
basically the main program reads a digital input which directly controls the run state of the routine.
the main program then displays the data.
int temperature, totalrun, currentrun;
createdaemon (1,turn_off_all_leds)
forever :{
DaemonState(counters) = digitalread(3)
daemonstate(runled) = digitalread(3)
daemonstate(overtemp) = (temperature >60) // fire his as long as we are too hot , sets the overtemp led to on
daemonstate(toocold) = (temperature < 10) // sets the toocold led to on
daemonstate(frostprotection) = (temperature <1) // opens a bleedvalve
lcdprint totalrun , currentrun,temperature
if digitalread(3) = 0 then currentrun=0;
}
since it runs on a hardware timer i don't care how long the lcd processing routine really takes. it will fire at exactly 1 second interval. as long as the called routines can all complete within the timer interval this program will run correctly. and 1 second is a very generous interval.