{"id":13781229,"url":"https://github.com/mkostrun/UBASIC-PLUS","last_synced_at":"2025-05-11T14:34:53.586Z","repository":{"id":207224392,"uuid":"120246131","full_name":"mkostrun/UBASIC-PLUS","owner":"mkostrun","description":"uBasic Plus for microcontrollers adds features to uBasic such as arrays and floating point numbers, more functions and ability to control hardware (analog read/write,digital write, et c.) all while improving internal workings of the interpreter. It is centered around ARM Cortex M0 processors.","archived":false,"fork":false,"pushed_at":"2018-03-17T10:52:05.000Z","size":283,"stargazers_count":24,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-17T16:42:31.486Z","etag":null,"topics":["basic","interpreter","microcontroller","stm32f0"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkostrun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-02-05T02:42:30.000Z","updated_at":"2024-10-09T20:09:31.000Z","dependencies_parsed_at":"2023-11-14T18:50:46.113Z","dependency_job_id":"45b39dcc-3ad3-44b5-a8d8-d49c7d224031","html_url":"https://github.com/mkostrun/UBASIC-PLUS","commit_stats":null,"previous_names":["mkostrun/ubasic-plus"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkostrun%2FUBASIC-PLUS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkostrun%2FUBASIC-PLUS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkostrun%2FUBASIC-PLUS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkostrun%2FUBASIC-PLUS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkostrun","download_url":"https://codeload.github.com/mkostrun/UBASIC-PLUS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253580350,"owners_count":21930928,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["basic","interpreter","microcontroller","stm32f0"],"created_at":"2024-08-03T18:01:24.060Z","updated_at":"2025-05-11T14:34:53.249Z","avatar_url":"https://github.com/mkostrun.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# UBASIC PLUS\n\nuBasicPlus is an extension of the uBasic by Adam Dunkels (2006),\nhttps://github.com/adamdunkels/ubasic, which includes\nthe strings and their functions from 'uBasic with strings' by David Mitchell (2008),\nhttp://www.zenoshrdlu.com/kapstuff/zsubasic.html,\nand some constructs and interpreter logic from 'CHDK', http://chdk.wikia.com/wiki/CHDK_Scripting_Cross_Reference_Page.\n\n## uBasic-Plus Interpreter Features\n\n### Software and Flow Control\n\n- UBASIC, which can be a small non-interactive interpreter of\nthe programming language BASIC which offers a subset of the commands\nthat are part of the language,\n26 integer variables, named 'a' through 'z',\n*if/then/else* with support for single symbol logical operators (\u003e,\u003c,=),\n*for/next*, *let*, *goto*, *gosub*, *print* and '\\n' (new line) as end-of-line character.\n\n- uBasic with strings, which adds support for strings:\n26 string variables, named a$-z$, string literals, variables and expressions can\nbe used in assignments and print statements string expressions can be compared\nfor equality in if statements string expressions can be concatenated using '+',\nand a number of string functions: *left$*, *mid$*, *right*, *str$*, *chr$*,\n*val*, *len$*, *instr$*, *asc*.\n\n  What is new in UBASIC-PLUS is that string scratch space (SSS) is introduced in which\nall string variables and intermediate results are stored using a structure\nheader (1byte) + data (strlen+1 bytes). At the end of each statement the SSS is cleared of all non-assigned\nstrings. This means that rather than pointers (size 4 bytes) the addresses in\nthe space are used (2 bytes). This caused all string functions to be rewritten.\nMost importantly, the garbage collection is done in place rather then by\ntemporarily doubling the storage space. The garbage collection now used is similar\nto the garbage collection done for managing arrays.\n\n- Elements of CHDK\n\n  The line numbering is removed and replaced by the labels CHDK-style\n\n  ```\n  :label1\n  ....\n  goto label1;\n  ```\n\n  What is new in UBASIC-PLUS is that when these labels are refered to in\ngoto/gosub this is done without quotation marks (unlike CHDK).\nFurthermore, in labels '_' can be used.\nNot even internally the lines are numbered (like it was the case with CHDK).\nRather, pointers are used to script string, meaning that the\nreturns - from gosub, for/next, if/then/else, while/endwhile - are\nfaster as they do not require searches (over line numbers).\n\n- Strings can be encompassed by single or double quotations. Tokenizer can identify labels.\n\n- End of line characters *'\\n'* and *';'*\n\n- *config.h*\n\n  Allows user to select which of the features below (if any) they want in their uBasic build.\n\n- Fixep point floats are implemented through Fixed Point Math Library for C\nby Ivan Voras and Tim Hartnick, https://sourceforge.net/projects/fixedptc.\nThe libary is enhanced with str_fixedpt function, which converts a string to fixed point float.\n\n- flow control\n  - more logical operators supported (\u003c\u003e,\u003c=,\u003e=,==,\u0026\u0026,||,!)\n  - complex logical expressions supported with use of brackets\n  - multi-line If/then/else/endif-command (CHDK-style)\n  - while/endwhile\n\n- *input {a,a$,a@(i)}, timeout_ms*\n\n   Wait at most until *timeout_ms* for input from the serial port. Wait is not executed\ninside the interpreter.\nRelies on external functions for serial-available and serial-read to be supplied as\ndocumented in *config.h* .\n\n\n- 26 fixed point arrays, a@ to z@, dynamically allocated using DIM command,\n  ```\n  dim a@(5);\n  for i = 1 to 5;\n    input a@(i),10000;\n  next i;\n  ```\n  In this example code expects 5 array entries to be entered through serial port, and\nwaits at most 10sec for each input to complete.\nIn the scripts or from the input line the numbers can be entered either directly\nas hex values,\n  ```\n  ... x = 0xaabbccdd\n  ```\n  or as binary values,\n  ```\n  ... x = 0b1101001\n  ```\n  or as decimal values,\n  ```\n  ... x = 123456[d,D,L,l]\n  ```\n  if the default fixed point float is not desired.\n\n\n- *println*\n\n  Same as *print* but adds an empty line at the end. Additional identifiers *hex* or *dec*\ncan be used to print the number as (hex)adecimal if fixed point floats are not desired, as\nin this example:\n  ```\n  ... println [hex,dec] x \n  ```\n\n- *sleep(f)*\n\n  Wait *f* seconds, which can be fixed point float.\nThis is not executed inside the BASIC interpreter.\n\n\n- *ran, uniform*\n\n  System random number generators based on the external function as documented in *config.h* .\nOn STM32 boards listed below, *ran* and *uniform* use two lowest bits after the analog read from\nthe internal temperature sensor. From multiple calls required number of random bits is collected.\n\n    - *ran* - generates random positive integer in fixed point float representation.\n\n    - *uniform* - generates random fixed point float in the range 0 to 0.999.\n\n\n- *tic(n), a=toc(n)*\n\n  rlabplus-type six timers for measuring the passed time from different breakpoints in the script\n\n- *sqrt, sin, cos, tan, exp, ln, pow*\n\n  fixed point arithmetic single argument functions from the fixed point math library.\n\n- *floor, ceil, round, abs*\n\n  fixed point float to fixed point integer arithmetic functions.\n\n- *clear*\n\n  Clears all variables, arrays and strings. It is good practice to put it as the\nfirst line of the script.\n\n\n\n### Hardware Control\n\n\n- *pinmode(pin,mode,speed), a=dread(pin), dwrite(pin,state)*\n\n  Allows direct control over digital pins.\n\n  - pin: \n\n    The pin designation follows their hardware\nnames, 0xa0:0xaf for pins 0 through 15 on port A, and so forth. It is up to user to verify\nthat particular pins are available for digital read/write operations.\nTied to hardware specific functions as described in *config.h* .\n\n  - mode: STM32 specific\n\n    Output: -2 for open drain, -1 for push-pull\n\n    Input:  0 for no pull, 1 for push-up, 2 for push-down.\n\n  - speed: STM specific\n\n    0 for low, 1 for medium and 2 for high frequency.\n\n- *awrite_conf(prescaler,period), awrite(channel,value), awrite(channel)*\n\n  direct control over output pins that support PWM on the micro-controller.\nThe *value* has to be in the range 0 to *period*-1.\nTied to hardware functions described in config.h\n\n\n- *i = flag(channel)*\n\n  Allow flags that can be set outside BASIC interpreter, e.g., using interrupts,\nto be used in flow control.\n  ```\n  :waithere\n      if (flag(1)==0) then goto waithere;\n  ```\n  In this example the script sits in this loop until the hardware event flag no. 1\ngets set by external process. Importantly, after the interpreter recognizes that the\nflag has been set, it immediately resets it so the subsequent calls will return 0\nuntil the flag is set again externally.\n\n  Importantly, while waiting for the flag, the microcontrolled does not sit inside the interpreter.\n\n- *aread_conf(duration,nreads), i = aread(channel)*\n\n  Read input from analog channels 0:18 from the microcontroller. The pin assignments of\nthe analog inputs for some microcontrollers is given in hardware examples below.\nSome channels may not be available.\n\n  - duration: STM specific\n\n    0 through 7 for varius preprogrammend duration of analog sampling and conversion, higher\nthe value longer the duration.\n\n  - nreads: value reported to the user will be an average of so many readings.\n\n\n- *store(x[x$,x@]), i=recall(x[x$,x@])*\n\n  Store and recall variable, string or array in FLASH. In that way variable can survive\nreboot of the device. The single page from FLASH is used as a scratch space, so when\nthere is no more space left on the page, the entire page is erased.\n\n\n### uBasic-Plus *Command Line Interface*\n\nThe Command Line Interface (CLI) supports the following commands:\n\n- *prog*\n\n  The CLI enters the line input mode. Everything entered on the serial port is considered\nas a sequential line in the script. Repeated execution of *prog* erases the previous script.\n\n- *run*\n\n  The CLI executes what ever has been assembled from multiple inputs as a BASIC script.\n\n- *cat*\n\n  Print the script that has been assembed so far.\n\n- *save*\n\n  exit the *prog* mode.\n\n- *edit*\n\n  enter the *prog* mode. Subsequent lines of input will be attached to already existing\nscript.\n\n- *demo N*\n\n  execute demo script number N.\n\n- *kill*\n\n  Stops the script if it is being executed, and returns control to command prompt.\n\n- If in *prog* mode, every typed line is added to the script until *save* or *run* is\nexecuted.\n\n- If not in *prog* mode, every typed line is executed as its own script, but the\nuBasic-Plus internal storage is not erased in between the executions.\n\nThe uBasic-Plus comprise of six files config.h, fixedptc.h, tokenizer.c,\ntokenizer.h, ubasic.c  and  ubasic.h.\nAs an example implementation of the hardware related functions (random number generation,\ngpio, hardware events, sleep and tic/toc) the development boards STM32F030-Nucleo64 and\nSTM32F051-Discovery are used in combination with CubeMX created system libraries.\n\n\n## UBASIC PLUS SCRIPT DEMOS\n\n\n### Demo 1 - warm up\n```\nprintln 'Demo 1 - Warm-up'\ngosub l1\nfor i = 1 to 2\n  for j = 1 to 2\n    println 'i,j=',i,j\n  next j\nnext i\nprintln 'Demo 1 Completed'\nend\n  :l1\nprintln 'subroutine'\nreturn\n```\n\n### Demo 2 - 'uBasic with strings' by David Mitchell\n```\nprintln 'Demo 2'\na$= 'abcdefghi'\nb$='123456789'\nprintln 'Length of a$=', len(a$)\nprintln 'Length of b$=', len(b$)\nif len(a$) = len(b$) then println 'same length'\nif a$ = b$ then println 'same string'\nc$=left$(a$+ b$,12)\nprintln c$\nc$=right$(a$+b$, 12)\nprintln c$\nc$=mid$(a$+b$, 8,8)\nprintln c$\nc$=str$(13+42)\nprintln c$\nprintln len(c$)\nprintln len('this' + 'that')\nc$ = chr$(34)\nprintln 'c$=' c$\nj = asc(c$)\nprintln 'j=' j\nprintln val('12345')\ni=instr(3, '123456789', '67')\nprintln 'position of 67 in 123456789 is', i\nprintln mid$(a$,2,2)+'xyx'\nprintln 'Demo 2 Completed'\nend\n```\n\n### Demo 3 - uBasic-Plus is here\n```\nprintln 'Demo 3 - Plus'\ntic(1)\nfor i = 1 to 2\n  j = i + 0.25 + 1/2\n  println 'j=' j\n  k = sqrt(2*j) + ln(4*i) + cos(i+j) + sin(j)\n  println 'k=' k\nnext i\n:repeat\n  if toc(1)\u003c=300 then goto repeat\nfor i = 1 to 2\nprintln 'ran(' i ')=' ran\nnext i\nfor i = 1 to 2\nprintln 'uniform(' i ')=' uniform\nnext i\nfor i = 1 to 2\nx = 10 * uniform\nprintln 'x=' x\nprintln 'floor(x)=' floor(x)\nprintln 'ceil(x)=' ceil(x)\nprintln 'round(x)=' round(x)\nprintln 'x^3=' pow(x,3)\nnext i\nprintln 'Digital Write Test'\npinmode(0xc0,-1,0)\npinmode(0xc1,-1,0)\npinmode(0xc2,-1,0)\npinmode(0xc3,-1,0)\nfor j = 0 to 2\n  dwrite(0xc0,(j % 2))\n  dwrite(0xc1,(j % 2))\n  dwrite(0xc2,(j % 2))\n  dwrite(0xc3,(j % 2))\n  sleep(0.5)\nnext j\nprintln 'Press the Blue Button or type kill!'\n:presswait\n  if flag(1)=0 then goto presswait\ntic(1)\nprintln 'Blue Button pressed!'\n:deprwait\n  if flag(2)=0 then goto deprwait\nprintln 'duration =' toc(1)\nprintln 'Blue Button de-pressed!'\nprintln 'Demo 3 Completed'\nend\n```\n\n### Demo 4 - input array entries in 10 sec time (use Arduino IDE Serial Terminal not Minicom)\n```\nprintln 'Demo 4 - Input with timeouts'\ndim a@(5)\nfor i = 1 to 5\n  print '?'\n  input a@(i),10000\nnext i\nprintln 'end of input'\nfor i = 1 to 5\n  println 'a(' i ') = ' a@(i)\nnext i\nprintln 'Demo 4 Completed'\nend\n```\n\n### Demo 5 - analog read with arrays\n```\nprintln 'Demo 5 - analog inputs and arrays';\nfor i = 1 to 100;\n  x = aread(16);\n  y = aread(17);\n  println 'VREF,TEMP=', x, y;\nnext i;\nfor i = 1 to 1;\n  n = floor(10 * uniform) + 2 ;\n  dim b@(n);\n  for j = 1 to n;\n    b@(j) = ran;\n    println 'b@(' j ')=' b@(j);\n  next j;\nnext i;\nprintln 'Demo 5 Completed';\nend;\n```\n\n### Demo 6 - if/then/else/endif and while/endwhile\n```\nprintln 'Demo 6: Multiline if, while'\nprintln 'Test If: 1'\nfor i=1 to 10 step 0.125\n  x = uniform\n  if (x\u003e=0.5) then\n    println x, 'is greater then 0.5'\n  else\n    println x, 'is smaller then 0.5'\n  endif\n  println 'i=' i\nnext i\nprintln 'End of If-test 1'\nprintln 'Test While: 1'\ni=10\nwhile ((i\u003e=0)\u0026\u0026(uniform\u003c=0.9))\n  i = i - 0.125\n  println 'i =', i\nendwhile\nprintln 'End of While-test 1'\nprintln 'Demo 6 Completed'\nend\n```\n\n### Demo 7 - kill test\n```\nprintln 'Demo 7: Analog Read or Kill'\ny=0\n:startover\n  x = aread(10)\n  if (abs(x-y)\u003e20) then\n    y = x\n    println 'x=',x\n  endif\n  sleep (0.2)\n  goto startover\nend\n```\n\n\n### Demo 8 - PWM Test\n```\nprintln 'Demo 8: analog write (PWM) 4-Channel Test'\np = 65536\nfor k = 1 to 10\n  p = p/2\n  awrite_conf(p,4096)\n  println 'prescaler = ' p\n  for i = 1 to 10\n    for j = 1 to 4\n      awrite(j,4095*uniform)\n    next j\n    println '    analog write = ' awrite(1),awrite(2),awrite(3),awrite(4)\n    sleep(5)\n  next i\nnext k\nawrite(1,0)\nawrite(2,0)\nawrite(3,0)\nawrite(4,0)\nend\n```\n\n### Demo 9 - Store/recall in FLASH Test\n```\nclear\nprintln 'Demo 9: store/recall with FLASH'\nif (recall(x)==0) then\n  println 'generating x'\n  x = uniform\n  store(x)\nendif\nprintln 'stored: x=' x\nif (recall(y@)==0) then\n  println 'generating y'\n  dim y@(10)\n  for i=1 to 10\n    y@(i) = uniform\n  next i\n  store(y@)\nendif\nprintln 'stored: y@'\nfor i=1 to 10\n  println '  y@('i')=' y@(i)\nnext i\nif (recall(s$)==0) then\n  println 'generating s'\n  s$='what is going on?'\n  store(s$)\nendif\nprintln 'stored: s$',s$\nprintln 'Demo 9 Completed'\nprintln 'Please run it once more'\nend\n```\n\n## UBASIC PLUS HARDWARE SUPPORT\n\n- STM32F0\n\n  For both boards a HAL UART library with RX using circular buffer was implemented and tested.\nThe library provides Arduino-type serial-available and serial-read functions. The library is\nthe same for both STM32F0 boards. The library is located in Drivers folder and should replace\nthe same by STM.\n\n\n### STM32F030R8-Nucleo64\n\nAbout the board:\n- Arm Cortex M0 64kb flash, 8kb ram, 48MHz frequency\n- GPIO: PC0, PC1, PC2, PC3\n- PWM:  Timer 3 Channels 1 (PA6), 2 (PA7), 3 (PB0) and 4 (PB1)\n- Analog Input: On STM32F0 these Channels are mapped to pins as follows 0:7 as A0:A7,\n8:9 as B0:B1, and 10:15 as C0:C5. Channel 16 is the temperature, and 17 the VREF.\n- Hardware Events:\n  - Blue Push Button 1 (PC13) with two events:\n    - button pressed - flag(1), and\n    - button depressed - flag(2)\n- sleep, tic/toc:\n\n  through *SysTick_Handler()* which counts in 1ms increments through interrupts\n\n- Serial Port\n\n  through USB connector used for debugging (UART2 on PA2/PA3)\n\n\n### STM32F051R8-Discovery\n\nAbout the board:\n- Arm Cortex M0 64kb flash, 8kb ram, 48MHz frequency\n- GPIO: PC0, PC1, PC2, PC3\n- PWM:  Timer 3 Channels 1 (PC6), 2 (PC7), 3 (PC8/LED4-blue) and 4 (PC9/LED3-green)\n- Analog Input: On STM32F0 these Channels are mapped to pins as follows 0:7 as A0:A7,\n8:9 as B0:B1, and 10:15 as C0:C5. Internal channel 16 is the temperature, and 17 the VREF.\n- Analog output: Channel 1.\n- Hardware Events:\n  - Blue Push Button 1 (PA0) with two events:\n    - button pressed - flag(1), and\n    - button depressed - flag(2)\n- sleep, tic/toc:\n\n  through *SysTick_Handler()* which counts in 1ms increments through interrupts\n\n- Serial Port\n\n  requires an additional USB/TTL cable (UART2 using PA2/PA3 on the discovery board)\n\n\n\nFirmware footprint with all features enabled and 8 demo scripts (bytes):\n37872 flash, 548 data and 3940 bss.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkostrun%2FUBASIC-PLUS","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkostrun%2FUBASIC-PLUS","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkostrun%2FUBASIC-PLUS/lists"}