How do I make a port of MicroPython for Casio calculators?

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Zezombye
Posts: 34
Joined: Mon Jul 30, 2018 8:29 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by Zezombye » Sat Dec 01, 2018 5:30 am

No, it's the string "from xxx import *":

Code: Select all

			char str[30];
			char filename[13];
			strcpy(filename, _sFile);
			filename[strlen(filename)-3] = '\0';
			
			sprintf(str, "from %s import *\r", filename);
			
			for (int k = 0; str[k]; k++) {
				str[k] = tolower2(str[k]);
			}
			
			_iAppMode = SHELL;
			
			mpy_main(str);
The actual text of the script is then retrieved by MPy with the import statement.

Now, the REPL calls the function mp_hal_stdout_tx_strn(const char *str, mp_uint_t len), which is just a wrapper for shell_print(str, len). The problem is simply that it sends char by char, and I have to update the display char by char (because I don't know when the string actually ends).

If I ignore the "len" argument and stop printing when I hit a \0, I can see that it actually sends strings, but with len=1. For example, printing "abcd" gives "abcdbcdcdd".

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by jickster » Sun Dec 02, 2018 3:45 am

Why and how have you refactored the py code?

You’re sending the first line into pyexec_friendly_repl() though that function is normally void.

If this is part of a script why are you using REPL functions?



Sent from my iPhone using Tapatalk Pro

Zezombye
Posts: 34
Joined: Mon Jul 30, 2018 8:29 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by Zezombye » Sun Dec 02, 2018 6:32 am

I refactored that because it was a simple way to automatically send the string "from xxx import *" to the shell.

So pyexec_friendly_repl(char *text), through a bunch of ifs, ultimately calls int readline(vstr_t *line, const char *prompt, char *text), which is the following function:

Code: Select all

int readline_index = 0;

int readline(vstr_t *line, const char *prompt, char *text) {
    readline_init(line, prompt);
	
	if (text != NULL) {
		for (;text[readline_index] != 0;) {
			int r;
			if (text[readline_index] != 0x0C) {
				if (text[readline_index] == '\n') {
					r = readline_process_char('\r');
				} else {
					r = readline_process_char(text[readline_index]);
				}
				readline_index++;
			} else {
				r = readline_process_char('\r');
				readline_index++;
			}
			if (r >= 0) {
				return r;
			}
		}
	}
	
    for (;;) {
		char str[45] = {0};
		
		if (waitForKey(str) == KEY_CTRL_EXIT) {
			return -KEY_CTRL_EXIT;
		}
		
		int charsAfterCursorCounter = 0;
		char countCharsAfterCursor = 0;
		
		for (int i = 0; str[i]; i++) {
			int c = str[i];
			
			if (c == '\a') {
				countCharsAfterCursor = 1;
			} else {
				
				if (countCharsAfterCursor) {
					charsAfterCursorCounter++;
				}
				
				int r = readline_process_char(c);
				if (r >= 0) {
					return r;
				}
			}
		}
		for (int i = 0; i < charsAfterCursorCounter; i++) {
			readline_process_char(CHAR_LEFT);
		}
    }
}
Basically: readline_index is the position in the sent text.
If readline_index is less than the length of the text, print the character of the text; else, listen for keys and print the string they send.

Though it's not a problem with readline; the REPL behaved that way since the very beginning, when I only overrode the mp_hal_stdout_tx_strn function to display to the screen. So my refactoring isn't the cause of this behavior, it's by default in MPy.

User avatar
boochow
Posts: 30
Joined: Sat Dec 16, 2017 9:36 am

Re: How do I make a port of MicroPython for Casio calculators?

Post by boochow » Tue Dec 04, 2018 7:55 am

FYI
CASIO releases MicroPython for fx-CG50 (Japanese version)

https://web.casio.jp/dentaku/fxcg50/python.html

Zezombye
Posts: 34
Joined: Mon Jul 30, 2018 8:29 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by Zezombye » Tue Dec 04, 2018 4:48 pm

Yeah, I knew about this port - in fact Casio not releasing MPy for monochrome calcs is why I'm doing this port myself :p

Shame they used the big font though, you could fit much more letters in the screen.

Zezombye
Posts: 34
Joined: Mon Jul 30, 2018 8:29 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by Zezombye » Thu Jan 03, 2019 1:15 pm

I "solved" the shell problem (really it's more like a workaround, it still kind of prints character by character, but I have no idea how to avoid that).

Basically I first reprogrammed shell_draw() to only execute in case of a new line (\n or character wrapping). This works fine, but now I also have to draw in case of a \0.

- First, reprogram readline() at /lib/mp-readline/readline.c to also send the \0 (I removed some fluff):

Code: Select all

int readline(vstr_t *line, const char *prompt, char *text) {
    readline_init(line, prompt);
	
    for (;;) {
		for (int i = 0; str[i]; i++) {
				int r = readline_process_char(c);
				if (r >= 0) {
					return r;
				}
		}
		readline_process_char('\0');
    }
}
Obviously reprogram readline_process_char() to call shell_draw() when it receives a \0.

- Second, simply make mp_hal_stdout_tx_str (/lib/utils/stdout_helpers.c) also send the \0:

Code: Select all

void mp_hal_stdout_tx_str(const char *str) {
    mp_hal_stdout_tx_strn(str, strlen(str)+1);
}
This normally takes care of all prints, and now the shell only updates the display line by line (which makes printing a long string MUCH faster).


Now, I have another bug (which could be a bug in MPy itself).

The following script enumerates all functions of a given module:

Code: Select all

#platforms: (0)TI-Nspire (1)NumWorks (2)Graph 90+E (3)Graph 75+E (4)TI-Python
plines=[29,12,  7, 9,11]
pcols =[53,99,509,32,32]
try:
  import sys
  try:
    if sys.platform=='nspire': platform=0
    if sys.platform=='TI-Python Adapter': platform=4
    platform=0
  except: platform=3
except:
  try:
    import kandinsky
    platform=1
  except:
    platform=2

nlines=plines[platform]
ncols=pcols[platform]
curline=0

def mprint(*ls):
  global curline
  st=""
  for s in ls:
    if not(isinstance(s,str)):
      s=str(s)
    st=st+s
  stlines=1+int(len(st)/ncols)
  if curline+stlines>=nlines:
    input("Input to continue:")
    curline=0
  print(st)
  curline+=stlines

def sstr(obj):
  try:
    s=obj.__name__
  except:
    s=str(obj)
    a=s.find("'")
    b=s.rfind("'")
    if a>=0 and b!=a:
      s=s[s.find("'")+1:s.rfind("'")]
  return s

def explmod(pitm,pitmsl=[],reset=True):
  global curline
  if(reset):
    curline=0
    pitmsl=[sstr(pitm)]
  hd="."*(len(pitmsl)-1)
  spath=".".join(pitmsl)
  c=0
  for itms in sorted(dir(pitm)):
    c=c+1
    try:
      itm=eval(spath+"."+itms)
      mprint(hd+itms+"="+str(itm))
      if spath.rfind(itms)<0:
        pitmsl2=pitmsl.copy()
        pitmsl2.append(itms)
        c=c+explmod(itm,pitmsl2,False)
    except:
      mprint(hd+itms)
  if c>0:
    mprint(hd+"Total: "+str(c)+" item(s)")
  return c
Output sample:
Image Image

The script works fine, however if I enable function attributes (MICROPY_PY_FUNCTION_ATTRS) the script crashes almost immediately:

Image
Image

The address 0x310A30 is the function bound_meth_attr():

Code: Select all

00310a14 <_bound_meth_attr>:
  310a14:       61 62           mov.l   @r6,r1
  310a16:       21 18           tst     r1,r1
  310a18:       8f 02           bf.s    310a20 <_bound_meth_attr+0xc>
  310a1a:       60 53           mov     r5,r0
  310a1c:       88 31           cmp/eq  #49,r0
  310a1e:       89 01           bt      310a24 <_bound_meth_attr+0x10>
  310a20:       00 0b           rts
  310a22:       00 09           nop
  310a24:       4f 22           sts.l   pr,@-r15
  310a26:       d0 06           mov.l   310a40 <_bound_meth_attr+0x2c>,r0       ! 31358c <_mp_obj_fun_get_name>
  310a28:       7f fc           add     #-4,r15
  310a2a:       54 41           mov.l   @(4,r4),r4
  310a2c:       40 0b           jsr     @r0
  310a2e:       2f 62           mov.l   r6,@r15
  310a30:       66 f2           mov.l   @r15,r6
  310a32:       40 08           shll2   r0
  310a34:       cb 02           or      #2,r0
  310a36:       26 02           mov.l   r0,@r6
  310a38:       7f 04           add     #4,r15
  310a3a:       4f 26           lds.l   @r15+,pr
  310a3c:       00 0b           rts
  310a3e:       00 09           nop
  310a40:       00 31           .word 0x0031
  310a42:       35 8c           add     r8,r5

Code: Select all

STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
    if (dest[0] != MP_OBJ_NULL) {
        // not load attribute
        return;
    }
    if (attr == MP_QSTR___name__) {
        mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(self_in);
        dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth));
    }
}
Any idea of what causes this crash?

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: How do I make a port of MicroPython for Casio calculators?

Post by jickster » Fri Jan 04, 2019 4:04 am

The crash is in mp_obj_fun_get_name.

Try commenting out the lines therein and adding them back one at a time.

If you have a debugger, it’s easier cause you can just put a breakpoint in mp_obj_fun_get_name and see where it dies.


Sent from my iPhone using Tapatalk Pro

Post Reply