diff --git a/.gitignore b/.gitignore index 2d20cb189..dce5decf8 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ user.props # MacOS desktop metadata files .DS_Store + +# vscode +.vscode/ \ No newline at end of file diff --git a/docs/sh/NWcompat_modules_en.md b/docs/sh/NWcompat_modules_en.md new file mode 100644 index 000000000..ba492d73f --- /dev/null +++ b/docs/sh/NWcompat_modules_en.md @@ -0,0 +1,120 @@ +# Using Numworks' modules `kandinsky`, `ion` and `time` with PythonExtra + +PythonExtra offers the possibility of using certain Numworks modules in order to make the scripts of this machine compatible as is on Casio fx-CG50 (no support on the fx9860G due to insufficient memory and lack of color screen ). + +This is a Work in Progress (WIP) and the support is subject to extensive testing at this stage. The port concerns the Numworks `kandinsky`, `ion` and `time` modules which are machine specific and are now supported via this implementation. The `math`, `cmath`, `random` modules being identical between the `Numworks` version and the `builtins` modules of MicroPython, they are therefore not part of this implementation but are perfectly usable without modification in the scripts. + +Note: the `turtle` and `matplotlib.pyplot` modules are not included in this implementation. It is possible to use the `turtle`, `matplotlib` and `casioplot` modules from Casio Education which are perfectly functional and provided as an example in `ports/sh/examples`. + + +## `kandinsky` + +The `kandinsky` module provides support for graphics primitives via high-performance `gint` routines. All the functions of this module are available: + +- `color(r,g,b)`: Generates the value of the color r,g,b. You can also simply use a tuple to define a color: (r,g,b). + +- `get_pixel(x,y)`: Returns the color of the pixel at x,y coordinates as a tuple (r,g,b). + +- `set_pixel(x,y,color)`: Lights the pixel x,y of the color color. + +- `draw_string(text,x,y,[color1],[color2])`: Displays the text at x,y coordinates. The arguments color1 (text color) and color2 (text background color) are optional. + +- `fill_rect(x,y,width,height,color)`: Fills a rectangle of width width and height height with the color color at the point of x and y coordinates. + +The module also offers a certain number of colors explicitly named and accessible by a character string. The following values ​​can be used instead of the color parameters of the `kandinsky` functions: +- "red", "r" +- "green", "g" +- "blue", "b" +- "black", "k" +- "white", "w" +- "yellow", "y" +- "pink" +- "magenta" +- "grey", "gray" +- "purple" +- "orange" +- "cyan" +- "brown" + +The following functions are additions to take advantage of the wide screen of the fxCG and are therefore an extension of the `Kandinsky` module. They are therefore by definition not compatible with Python Numwork. These functions can be recognized by their names which all begin with `CGEXT_`: + +- `CGEXT_Enable_Wide_Screen()`: Enables the fxCG wide screen, no settings are necessary. The x-coordinates of the physical screen can be negative to encroach on the left white stripe and greater than 319 pixels to encroach on the right white stripe; + +- `CGEXT_Disable_Wide_Screen()`: Cancels the activation of the fxCG extended screen, no settings are necessary. The x coordinates of the physical screen will be constrained between 0 and 320 pixels. Beyond that, the route will not be carried out. + +- `CGEXT_Is_Wide_Screen_Enabled()`: Returns `True` if the extended screen is active and `False` otherwise. + +- `CGEXT_Set_Margin_Color( color )` : Paints the margin of the `Numworks` screen on fxCG with the specified color. + +Note 1: after having made a plot in the extended area, it must be active to allow its deletion (typically via a call to the `fill_rect()` function with the appropriate parameters). + +Note 2: In non-extended mode (by default when initializing the `Kandinsky` module) the screen coordinates go from (0,0) to (319,221) centered on the fxCG screen. In extended mode, the screen coordinates range from (-38,-1) to (358,223). + + +## `ion` + +The `ion` module gives access to the `keydown(k)` function which returns True if the key k placed as an argument is pressed and False otherwise. + +The “conversion” of the keys between the Numworks machine and Casio fxCG50 is done according to the following mapping: + +| Numworks | Casio fxCG50 | Numworks Key # | +|----------|--------------|---------------------| +| KEY_LEFT | KEY_LEFT | 0 | +| KEY_UP | KEY_UP | 1 | +| KEY_DOWN | KEY_DOWN | 2 | +| KEY_RIGHT | KEY_RIGHT | 2 | +| KEY_OK | KEY_F1 | 4 | +| KEY_BACK | KEY_EXIT | 5 | +| KEY_HOME | KEY_MENU | 6 | +| KEY_ONOFF | KEY_ACON | 7 | +| ... | ... | ... | +| KEY_SHIFT | KEY_SHIFT | 12 | +| KEY_ALPHA | KEY_ALPHA | 13 | +| KEY_XNT | KEY_XOT | 14 | +| KEY_VAR | KEY_VARS | 15 | +| KEY_TOOLBOX | KEY_OPTN | 16 | +| KEY_BACKSPACE | KEY_DEL | 17 | +| KEY_EXP | KEY_EXP | 17 | +| KEY_LN | KEY_LN | 19 | +| KEY_LOG | KEY_LOG | 20 | +| KEY_IMAGINARY | KEY_F2 | 21 | +| KEY_COMMA | KEY_COMMA | 22 | +| KEY_POWER | KEY_POWER | 23 | +| KEY_SINE | KEY_SIN | 24 | +| KEY_COSINE | KEY_COS | 25 | +| KEY_TANGENT | KEY_TAN | 26 | +| KEY_PI | KEY_F3 | 27 | +| KEY_SQRT | KEY_F4 | 28 | +| KEY_SQUARE | KEY_SQUARE | 29 | +| KEY_SEVEN | KEY_7 | 30 | +| KEY_EIGHT | KEY_8 | 31 | +| KEY_NINE | KEY_9 | 32 | +| KEY_LEFTPARENTHESIS | KEY_LEFTP | 33 | +| KEY_RIGHTPARENTHESIS | KEY_RIGHTP | 34 | +| ... | ... | ... | +| KEY_FOUR | KEY_4 | 36 | +| KEY_FIVE | KEY_5 | 37 | +| KEY_SIX | KEY_6 | 38 | +| KEY_MULTIPLICATION | KEY_MUL | 39 | +| KEY_DIVISION | KEY_DIV | 40 | +| ... | ... | ... | +| KEY_ONE | KEY_1 | 42 | +| KEY_TWO | KEY_2 | 43 | +| KEY_THREE | KEY_3 | 44 | +| KEY_PLUS | KEY_ADD | 45 | +| KEY_MINUS | KEY_SUB | 46 | +| ... | ... | ... | +| KEY_ZERO | KEY_0 | 48 | +| KEY_DOT | KEY_DOT | 49 | +| KEY_EE | KEY_F5 | 50 | +| KEY_ANS | KEY_NEG | 51 | +| KEY_EXE | KEY_EXE | 52 | + + +## `time` + +The `time` module gives access to two functions: + +- `monotonic()`: Returns the clock value at the time the function is called. + +- `sleep(t)`: Suspends execution for t seconds. diff --git a/docs/sh/NWcompat_modules_fr.md b/docs/sh/NWcompat_modules_fr.md new file mode 100644 index 000000000..6f2a70170 --- /dev/null +++ b/docs/sh/NWcompat_modules_fr.md @@ -0,0 +1,120 @@ +# Utilisation des modules `kandinsky`, `ion` et `time` de l'implémentation Python `Numworks` + +PythonExtra offre la possibilité d'utiliser certains modules de la Numworks afin de rendre les scripts de cette machine compatible en l'état sur Casio fx-CG50 (pas de support sur la fx9860G pour cause de mémoire insuffisante et d'abence d'écran couleur). + +Il s'agit d'un Work in Progress (WIP) et le support est sujet à tests approfondis à ce stade. Le port concerne les modules `kandinsky`, `ion` et `time` de la Numworks qui sont spécifiques à la machine et sont désormais supportés via cette implémentation. Les modules `math`, `cmath`, `random` étant identiques entre la version `Numworks` et les modules `builtins` de MicroPython, ils ne font donc pas partie de cette implémentation mais sont parfaitement utilisables sans modification dans les scripts. + +Note : les modules `turtle` et `matplotlib.pyplot` ne sont pas repris dans cette implémentation. Il est possible d'utiliser les modules `turtle`, `matplotlib` et `casioplot` de Casio Education qui sont parfaitement fonctionnels et fournis en example dans `ports/sh/examples`. + + +## `kandinsky` + +Le module `kandinsky` offre le support des primitives graphiques via les routines hautes performance de `gint`. Toutes les fonctions de ce module sont disponibles : + +- `color(r,g,b)` : Génère la valeur de la couleur r,g,b. Vous pouvez aussi simplement utiliser un tuple pour définir une couleur : (r,g,b). + +- `get_pixel(x,y)` : Renvoie la couleur du pixel aux coordonnées x,y sous forme de tuple (r,g,b). + +- `set_pixel(x,y,color)` : Allume le pixel x,y de la couleur color. + +- `draw_string(text,x,y,[color1],[color2])` : Affiche le texte text aux coordonnées x,y. Les arguments color1 (couleur du texte) et color2 (couleur de lʼarrière plan du texte) sont optionnels. + +- `fill_rect(x,y,width,height,color)` : Remplit un rectangle de largeur width et de hauteur height avec la couleur color au point de coordonnées x et y. + +Le module offre de plus un certain nombre de couleurs explicitement nommées et accessibles par une chaine de caractères. Les valeurs suivantes sont utilisables en lieu et place des paramètres de couleur des fonctions de `kandinsky` : +- "red", "r" +- "green", "g" +- "blue", "b" +- "black", "k" +- "white", "w" +- "yellow", "y" +- "pink" +- "magenta" +- "grey", "gray" +- "purple" +- "orange" +- "cyan" +- "brown" + +Les fonctions suivantes sont des ajouts pour tirer partie de l'écran large de la fxCG et qui sont donc une extension du module `Kandinsky`. Elles ne sont donc par définition pas compatible avec le Python Numwork. Ces fonctions sont reconnaisables à leurs appellations qui commencent toutes par `CGEXT_` : + +- `CGEXT_Enable_Wide_Screen()` : Active l'écran étendu de la fxCG, aucun paramètre n'est nécessaire. Les coordonnées x de l'écran physique peuvent être négatives pour empiéter sur la bande blanche de gauche et supérieures à 319 pixels pour empièter sur la bande blanche de droite; + +- `CGEXT_Disable_Wide_Screen()` : Annule l'activation de l'écran étendu de la fxCG, aucun paramètre n'est nécessaire. Les coordonnées x de l'écran physique seront contraintes entre 0 et 320 pixels. Au-delà, le tracé ne sera pas effectué. + +- `CGEXT_Is_Wide_Screen_Enabled()` : Retourne `True` si l'écran étendu est actif et `False` dans le cas contraire. + +- `CGEXT_Set_Margin_Color( color )` : Trace les marge de la fxCG50 (pourtours de l'écran `Numworks`) de la couleur passée en argument. + +Note 1 : après avoir réalisé un tracé dans la zone étendue, il faut que celle-ci soit active pour permettre son effacement (typiquement via un appel à la fonction `fill_rect()` avec les paramètres adéquats). + +Note 2 : En mode non étendu (par défaut à l'initialisation du module `Kandinsky`) les coordonnées de l'écran vont de (0,0) à (319,221) centré sur l'écran de la fxCG. En mode étendu, les coordonnées de l'écran vont de (-38,-1) à (358,223). + + +## `ion` + +Le module `ion` donne accès à la fonction `keydown(k)` qui renvoie True si la touche k placée en argument est appuyée et False sinon. + +La "conversion" des touches entre la machine Numworks et Casio fxCG50 se fait selon le mapping suivant : + +| Numworks | Casio fxCG50 | Numworks Key # | +|----------|--------------|---------------------| +| KEY_LEFT | KEY_LEFT | 0 | +| KEY_UP | KEY_UP | 1 | +| KEY_DOWN | KEY_DOWN | 2 | +| KEY_RIGHT | KEY_RIGHT | 2 | +| KEY_OK | KEY_F1 | 4 | +| KEY_BACK | KEY_EXIT | 5 | +| KEY_HOME | KEY_MENU | 6 | +| KEY_ONOFF | KEY_ACON | 7 | +| ... | ... | ... | +| KEY_SHIFT | KEY_SHIFT | 12 | +| KEY_ALPHA | KEY_ALPHA | 13 | +| KEY_XNT | KEY_XOT | 14 | +| KEY_VAR | KEY_VARS | 15 | +| KEY_TOOLBOX | KEY_OPTN | 16 | +| KEY_BACKSPACE | KEY_DEL | 17 | +| KEY_EXP | KEY_EXP | 17 | +| KEY_LN | KEY_LN | 19 | +| KEY_LOG | KEY_LOG | 20 | +| KEY_IMAGINARY | KEY_F2 | 21 | +| KEY_COMMA | KEY_COMMA | 22 | +| KEY_POWER | KEY_POWER | 23 | +| KEY_SINE | KEY_SIN | 24 | +| KEY_COSINE | KEY_COS | 25 | +| KEY_TANGENT | KEY_TAN | 26 | +| KEY_PI | KEY_F3 | 27 | +| KEY_SQRT | KEY_F4 | 28 | +| KEY_SQUARE | KEY_SQUARE | 29 | +| KEY_SEVEN | KEY_7 | 30 | +| KEY_EIGHT | KEY_8 | 31 | +| KEY_NINE | KEY_9 | 32 | +| KEY_LEFTPARENTHESIS | KEY_LEFTP | 33 | +| KEY_RIGHTPARENTHESIS | KEY_RIGHTP | 34 | +| ... | ... | ... | +| KEY_FOUR | KEY_4 | 36 | +| KEY_FIVE | KEY_5 | 37 | +| KEY_SIX | KEY_6 | 38 | +| KEY_MULTIPLICATION | KEY_MUL | 39 | +| KEY_DIVISION | KEY_DIV | 40 | +| ... | ... | ... | +| KEY_ONE | KEY_1 | 42 | +| KEY_TWO | KEY_2 | 43 | +| KEY_THREE | KEY_3 | 44 | +| KEY_PLUS | KEY_ADD | 45 | +| KEY_MINUS | KEY_SUB | 46 | +| ... | ... | ... | +| KEY_ZERO | KEY_0 | 48 | +| KEY_DOT | KEY_DOT | 49 | +| KEY_EE | KEY_F5 | 50 | +| KEY_ANS | KEY_NEG | 51 | +| KEY_EXE | KEY_EXE | 52 | + + +## `time` + +Le module `time` donne accès à deux fonctions : + +- `monotonic()` : Renvoie la valeur de lʼhorloge au moment où la fonction est appelée. + +- `sleep(t)` : Suspend lʼexécution pendant t secondes. diff --git a/ports/fx9860g3/Makefile b/ports/fx9860g3/Makefile index a49a16024..a34f28323 100644 --- a/ports/fx9860g3/Makefile +++ b/ports/fx9860g3/Makefile @@ -1,6 +1,7 @@ include ../../py/mkenv.mk SH_CFLAGS := -DFX9860G +TARGETCASIO := "FX9860G" SH_LDFLAGS := -T fx9860g.ld -ljustui-fx -lm -lgint-fx -lc -lgint-fx -lgcc SH_ASSETS := \ diff --git a/ports/fxcg50/.gitignore b/ports/fxcg50/.gitignore index b6d29c07b..c5c5c4998 100644 --- a/ports/fxcg50/.gitignore +++ b/ports/fxcg50/.gitignore @@ -1,2 +1,2 @@ /icon.xcf -/PythonExtra.g3a +/*.g3a \ No newline at end of file diff --git a/ports/fxcg50/Makefile b/ports/fxcg50/Makefile index 5cac3523a..93dd1722f 100644 --- a/ports/fxcg50/Makefile +++ b/ports/fxcg50/Makefile @@ -1,16 +1,17 @@ include ../../py/mkenv.mk SH_CFLAGS := -DFXCG50 +TARGETCASIO := "FXCG50" SH_LDFLAGS := -T fxcg50.ld -ljustui-cg -lm -lgint-cg -lc -lgint-cg -lgcc -SH_ASSETS := img_modifier_states.png font_9.png font_13.png font_19.png +SH_ASSETS := img_modifier_states.png font_9.png font_13.png font_19.png PoliceNW SH_METADATA := fxconv-metadata.txt SH_CONVFLAGS := --cg - + all: PythonExtra.g3a PythonExtra.g3a: $(BUILD)/firmware.bin icon-uns.png icon-sel.png - fxgxa --g3a -n PythonExtra --icon-uns=icon-uns.png --icon-sel=icon-sel.png $< -o $@ + fxgxa --g3a -n PyExtra_NW --icon-uns=icon-uns.png --icon-sel=icon-sel.png $< -o $@ send: all fxlink -sw PythonExtra.g3a diff --git a/ports/fxcg50/PoliceNW/U+0020.png b/ports/fxcg50/PoliceNW/U+0020.png new file mode 100644 index 000000000..247fb3204 Binary files /dev/null and b/ports/fxcg50/PoliceNW/U+0020.png differ diff --git a/ports/fxcg50/PoliceNW/U+00A0.png b/ports/fxcg50/PoliceNW/U+00A0.png new file mode 100644 index 000000000..3f35f948c Binary files /dev/null and b/ports/fxcg50/PoliceNW/U+00A0.png differ diff --git a/ports/fxcg50/fxconv-metadata.txt b/ports/fxcg50/fxconv-metadata.txt index 47bff3b83..be1380ab6 100644 --- a/ports/fxcg50/fxconv-metadata.txt +++ b/ports/fxcg50/fxconv-metadata.txt @@ -29,3 +29,12 @@ font_19.png: grid.padding: 0 grid.border: 0 proportional: true + +PoliceNW: + name: numworks + type: font + charset: unicode + grid.size: 10x16 + grid.padding: 0 + grid.border: 0 + proportional: true \ No newline at end of file diff --git a/ports/fxcg50/icon-selNW.png b/ports/fxcg50/icon-selNW.png new file mode 100644 index 000000000..fa0976934 Binary files /dev/null and b/ports/fxcg50/icon-selNW.png differ diff --git a/ports/fxcg50/icon-selNWUSB.png b/ports/fxcg50/icon-selNWUSB.png new file mode 100644 index 000000000..49ebe14bf Binary files /dev/null and b/ports/fxcg50/icon-selNWUSB.png differ diff --git a/ports/fxcg50/icon-unsNW.png b/ports/fxcg50/icon-unsNW.png new file mode 100644 index 000000000..d482eebfc Binary files /dev/null and b/ports/fxcg50/icon-unsNW.png differ diff --git a/ports/fxcg50/icon-unsNWUSB.png b/ports/fxcg50/icon-unsNWUSB.png new file mode 100644 index 000000000..e2aaf60da Binary files /dev/null and b/ports/fxcg50/icon-unsNWUSB.png differ diff --git a/ports/sh/.gitignore b/ports/sh/.gitignore index 4c56413a8..5e1a9905c 100644 --- a/ports/sh/.gitignore +++ b/ports/sh/.gitignore @@ -1,2 +1,3 @@ /exclude/ /PythonExtra*.zip +/numworks/ion_backup.c diff --git a/ports/sh/Makefile b/ports/sh/Makefile index e23b8c153..ccaca7464 100644 --- a/ports/sh/Makefile +++ b/ports/sh/Makefile @@ -31,6 +31,29 @@ SRC_QSTR += \ ports/sh/objgintimage.c \ ports/sh/pyexec.c \ + +ifeq ($(TARGETCASIO),"FXCG50") + $(info ************ FXCG50 VERSION ************ ) + $(info ********* Add Numworks modules ********* ) + SRC_C += \ + ports/sh/numworks/modkandinsky.c \ + ports/sh/numworks/ion.c \ + ports/sh/numworks/time.c \ + + SRC_QSTR += \ + ports/sh/numworks/modkandinsky.c \ + ports/sh/numworks/ion.c \ + ports/sh/numworks/time.c + + +endif + +ifeq ($(TARGETCASIO),"FX9860G") + $(info *********** FX9860G VERSION *********** ) + +endif + + ASSETS_O := $(SH_ASSETS:%=$(BUILD)/sh_assets/%.o) OBJ = $(PY_O) $(ASSETS_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/ports/sh/debug.c b/ports/sh/debug.c index 3c2b436b0..1cec7f702 100644 --- a/ports/sh/debug.c +++ b/ports/sh/debug.c @@ -125,4 +125,9 @@ void pe_debug_run_videocapture(void) } } +void pe_debug_close(void) +{ + usb_close(); +} + #endif /* PE_DEBUG */ diff --git a/ports/sh/debug.h b/ports/sh/debug.h index 293169817..f531c9835 100644 --- a/ports/sh/debug.h +++ b/ports/sh/debug.h @@ -39,6 +39,9 @@ void pe_debug_toggle_videocapture(void); /* Send a video capture frame if video capture is enabled. */ void pe_debug_run_videocapture(void); +/* Close the debugging ressources */ +void pe_debug_close(void); + #if !PE_DEBUG #define PE_DEBUG_NOOP do {} while(0) #define pe_debug_init(...) PE_DEBUG_NOOP @@ -47,6 +50,7 @@ void pe_debug_run_videocapture(void); #define pe_debug_screenshot(...) PE_DEBUG_NOOP #define pe_debug_toggle_videocapture(...) PE_DEBUG_NOOP #define pe_debug_run_videocapture(...) PE_DEBUG_NOOP +#define pe_debug_close(...) PE_DEBUG_NOOP #endif #endif /* __PYTHONEXTRA_DEBUG_H */ diff --git a/ports/sh/examples/numworks/NW_pacman_original.py b/ports/sh/examples/numworks/NW_pacman_original.py new file mode 100644 index 000000000..52af608c0 --- /dev/null +++ b/ports/sh/examples/numworks/NW_pacman_original.py @@ -0,0 +1,223 @@ +# PacMan par Kevin FEDYNA +# https://nsi.xyz/numapps/pac-man-en-python-numworks/ + +from kandinsky import fill_rect, draw_string +from ion import keydown +from math import sqrt +from random import randint +from time import monotonic + +try: + from kandinsky import get_keys + color = (192, 53, 53) +except: + color = (255, 183, 52) + +terrain = (262143,131841,187245,187245,131073,186285,135969,252783,249903,251823,1152,251823,249903,251823,131841,187245,147465,219051,135969,195453,131073,262143) +bits = 18 +width = 320 +height = 222 +colors = ((0, 0, 0), (32, 48, 248), (248, 224, 8), tuple(color)) +ghost_color = ((255, 184, 255), (255, 0,0), (255, 184, 82), (0, 255, 255)) +pacgommes = [0,130302,9360,74898,131070,75858,126174,8208,8208,8208,8208,8208,8208,8208,130302,74898,49140,43092,126174,66690,131070,0] +superpacgommes = [0,0,65538,0,0,0,0,0,0,0,0,0,0,0,0,0,65538,0,0,0,0,0,0] +frightened = 0 +lives = 2 +won = 0 +lvl = 0 +score = 0 +chained = 0 + + +class Entity: + def __init__(self, x, y, clr, d=0): + self.x = x + self.y = y + self.d = d + self.nd = d + self.f = 0 + self.out = 0 + self.color = clr + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,self.color) + def espace(self,dx=-1,dy=-1): + if dx == dy: + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[self.nd] + return not terrain[int(self.y + 5.5*dy)]>>(bits-1-int(self.x + 5.5*dx)) & 1 and ((dx != 0 and self.y%1 == 0.5) or (dy != 0 and self.x%1== 0.5)) + def move(self): + global frightened, ghosts, score, chained, lives, total, won + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[self.d] + if self.espace(dx,dy): + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,colors[0]) + self.x = (round(self.x + dx, 1) - 0.5) % 16.5 + 0.5 + self.y = round(self.y + dy, 1) + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,self.color) + if self.color == colors[2]: + if pacgommes[int(self.y)] >> (bits - 1 - int(self.x)) & 1: + pacgommes[int(self.y)] -= 1 << (bits - 1 - int(self.x)) + score += 10 + if superpacgommes[int(self.y)] >> (bits - 1 - int(self.x)) & 1: + superpacgommes[int(self.y)] -= 1 << (bits - 1 - int(self.x)) + score += 50 + chained = 0 + frightened = monotonic() + for g in ghosts: + if g.out: + g.color = colors[1] + g.d = (3, 2, 1, 0)[g.d] + g.f = 1 + for g in range(4): + if sqrt((self.x-ghosts[g].x)**2+(self.y-ghosts[g].y)**2) < 0.6: + if ghosts[g].f: + chained += 1 + total += 1 + score += (1 << chained)*100 + ghosts[g].f = 0 + ghosts[g].color = ghost_color[g] + ghosts[g].x = 9 + ghosts[g].y = 8.5 + if total == 16: + score += 12000 + else: + for gp in range(4): + ghosts[gp].f = 0 + ghosts[gp].color = ghost_color[gp] + ghosts[gp].x = 9 + ghosts[gp].y = 10.5 + ghosts[gp].out = 0 + self.x = 9 + self.y = 16.5 + self.d, self.nd = 0, 0 + lives -= 1 + return render() + if not won and score > 10000: + lives += 1 + won = 1 + px, py = int(self.x - 5.5*dx), int(self.y - 5.5*dy) + if pacgommes[py]>>(bits-1-px) & 1: + fill_rect(px*10+144,py*10+5,2,2,(250, 207, 173)) + if superpacgommes[py]>>(bits-1-px) & 1: + fill_rect(px*10+143,py*10+4,4,4,(250, 207, 173)) + def ia(self,x,y): + if self.f: + while True: + d = randint(0,3) + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[d] + if d != (3,2,1,0)[self.d] and self.espace(dx,dy): + self.d = d + break + else: + distances = [9999 for _ in range(4)] + for i in range(4): + if i != (3,2,1,0)[self.d]: + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[i] + if self.espace(dx,dy): + distances[i] = sqrt((self.y + dy - y)**2 + (self.x + dx - x)**2) + self.d = distances.index(min(distances)) + +def prebuild(): + fill_rect(0,0,width,height,colors[0]) + fill_rect(138, 0, 2, height, colors[3]) + draw_string("PAC-MAN", 35, 10, colors[3], colors[0]) + draw_string("nsi.xyz/pacman", 0, 204,colors[0], colors[3]) + draw_string("Score :", 35, 40, (255,)*3, colors[0]) + draw_string("Niveau :", 30, 90, (255,)*3, colors[0]) + +def render(): + global terrain, pacgommes, superpacgommes, lives, arrivee + if lives == -1: + return 42 + draw_string(str(lvl),70-5*len(str(lvl)),110,(255,)*3,colors[0]) + fill_rect(0,150,138,20,colors[0]) + for i in range(lives): + fill_rect(60-(lives-1)*20+i*40,150,20,20,colors[2]) + for l in range(len(terrain)): + for c in range(bits): + fill_rect(c*10+140,l*10+1,10,10,colors[0]) + if pacgommes[l]>>(bits-1-c) & 1: + fill_rect(c*10+144,l*10+5,2,2,(250, 207, 173)) + if superpacgommes[l]>>(bits-1-c) & 1: + fill_rect(c*10+143,l*10+4,4,4,(250, 207, 173)) + if terrain[l]>>(bits-1-c) & 1: + for d in ((1,0),(0,1),(-1,0),(0,-1)): + if 0 <= l + d[0] <= len(terrain) - 1 and 0 <= c + d[1] <= bits - 1 and not terrain[l + d[0]]>>(bits-1-(c+d[1])) & 1: + fill_rect(c*10+140+9*(d[1]==1),l*10+1+9*(d[0]==1),1+9*(d[1]==0),1+9*(d[0]==0),colors[1]) + arrivee = monotonic() + +def engine(): + global frightened, ghosts, pacgommes, superpacgommes, lvl, arrivee, total + while True: + pacgommes = [0,130302,9360,74898,131070,75858,126174,8208,8208,8208,8208,8208,8208,8208,130302,74898,49140,43092,126174,66690,131070,0] + superpacgommes = [0,0,65538,0,0,0,0,0,0,0,0,0,0,0,0,0,65538,0,0,0,0,0,0] + lvl += 1 + total = 0 + render() + pacman = Entity(9, 16.5, colors[2]) + ghosts = [Entity(9, 10.5, ghost_color[i]) for i in range(4)] + while sum(pacgommes) + sum(superpacgommes): + depart = monotonic() + for i in range(4): + if keydown(i): + if i == (3,2,1,0)[pacman.d]: + pacman.d = i + pacman.nd = i + while monotonic() - depart < 0.01: + if pacman.espace(): + pacman.d = pacman.nd + if pacman.move() == 42: + draw_string("GAME OVER",185,100,colors[3],colors[0]) + return 69 + + draw_string(str(score),70-5*len(str(score)),60,(255,)*3,colors[0]) + + """ Fantomes """ + + if frightened: + if monotonic() - frightened > 6.5: + for g in ghosts: + if g.f: + g.color = (255,)*3 + if monotonic() - frightened > 8.5: + frightened = 0 + for g in range(4): + ghosts[g].color = ghost_color[g] + ghosts[g].f = 0 + + if arrivee: + if monotonic() - arrivee > 0 and not ghosts[1].out: + ghosts[1].out = 1 + ghosts[1].y = 8.5 + if monotonic() - arrivee > 2.5 and not ghosts[0].out: + ghosts[0].out = 1 + ghosts[0].y = 8.5 + if monotonic() - arrivee > 5 and not ghosts[3].out: + ghosts[3].out = 1 + ghosts[3].y = 8.5 + if monotonic() - arrivee > 7.5 and not ghosts[2].out: + ghosts[2].out = 1 + ghosts[2].y = 8.5 + fill_rect(220,101,20,10,colors[0]) + arrivee = 0 + + pdx, pdy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[pacman.d] + + # Pinky + ghosts[0].ia(pacman.x + 20 * pdx, pacman.y + 20 * pdy) + ghosts[0].move() + + # Inky + ghosts[3].ia(max(min(ghosts[1].x + 2*(pacman.x + 20 * pdx - ghosts[1].x), 16.5), 1.5), max(min(ghosts[1].y +2*(pacman.y + 20 * pdy - ghosts[1].y), 21.5), 1.5)) + ghosts[3].move() + + # Blinky + ghosts[1].ia(pacman.x, pacman.y) + ghosts[1].move() + + # Clyde + if sqrt((ghosts[2].x - pacman.x)**2 + (ghosts[2].y - pacman.y)**2) > 4: + ghosts[2].ia(pacman.x, pacman.y) + else: + ghosts[2].ia(1.5, 20.5) + ghosts[2].move() + +prebuild() +engine() diff --git a/ports/sh/examples/numworks/NW_snake_origin.py b/ports/sh/examples/numworks/NW_snake_origin.py new file mode 100644 index 000000000..93621dd3e --- /dev/null +++ b/ports/sh/examples/numworks/NW_snake_origin.py @@ -0,0 +1,303 @@ +# Snake from Golem64 +# https://my.numworks.com/python/golem64/snake + +#Version 1.7 STABLE +#Tip: You should try to press +#some keys in the menu... +from random import * +from kandinsky import * +from ion import * +from time import * +#from pomme import * +def oscolor(): + try: + get_keys() + except: + return 'orange' + else: + return 'red' +def lastPos(i,x,y): + if i[-1]==3: + pos=[x-10,y] + elif i[-1]==2: + pos=[x,y-10] + elif i[-1]==0: + pos=[x+10,y] + elif i[-1]==1: + pos=[x,y+10] + pos[0],pos[1]=checkTeleport(pos[0],pos[1]) + return pos +def newApple(appleC,bgC): + applex=randint(0,31)*10+4 + appley=randint(0,21)*10+5 + while get_pixel(applex,appley)!=bgC: + applex=randint(0,31)*10+4 + appley=randint(0,21)*10+5 + fill_rect(applex-4,appley-4,10,10,appleC) + return applex,appley +def checkTeleport(x,y): + if x<4: + x=314 + if x>314: + x=4 + if y<5: + y=215 + if y>215: + y=5 + return x,y +def getMove(u): + for k in range(4): + if keydown(k)==True and u+k!=3: return k + return u +def clearDraw(): fill_rect(0,0,320,222,(255,255,255)) +def clearHome(): print("\n \n \n \n \n \n \n \n \n \n \n \n \n ") +def redraw(): + draw_string("(DELETE to exit)",0,0) + printLetter([1,1,1,1,0,0,1,1,1,0,0,1,1,1,1],70,80,10,(0,204,0)) + fill_rect(95,80,2,4,(0,0,0)) + fill_rect(95,86,2,4,(0,0,0)) + fill_rect(100,84,4,2,(255,0,0)) + fill_rect(104,82,2,2,(255,0,0)) + fill_rect(104,86,2,2,(255,0,0)) + printLetter([1,1,1,1,0,1,1,0,1,1,0,1,1,0,1],110,80,10,(0,0,0)) + printLetter([1,1,1,1,0,1,1,1,1,1,0,1,1,0,1],150,80,10,(0,0,0)) + printLetter([1,0,1,1,0,1,1,1,0,1,0,1,1,0,1],190,80,10,(0,0,0)) + printLetter([1,1,1,1,0,0,1,1,1,1,0,0,1,1,1],230,80,10,(0,0,0)) +def printLetter(letter,x,y,size,color): + for yi in range(5): + for xi in range(3): + if letter[yi*3+xi]==1: + fill_rect(x+(xi*size),y+(yi*size),size,size,color) +def menu(): + clearDraw() + printLetter([1,1,1,1,0,1,1,0,1,1,0,1,1,0,1],110,80,10,(0,0,0)) + printLetter([1,1,1,1,0,1,1,1,1,1,0,1,1,0,1],150,80,10,(0,0,0)) + printLetter([1,0,1,1,0,1,1,1,0,1,0,1,1,0,1],190,80,10,(0,0,0)) + printLetter([1,1,1,1,0,0,1,1,1,1,0,0,1,1,1],230,80,10,(0,0,0)) + anim=[1,1,1,1,1,1,1,1,1,4,4,3,3,4,4,1,1] + ax=0 + ay=120 + aendx=-110 + aendy=120 + u=1 + aback=0 + for i in range(len(anim)): + ax=ax+((anim[i]==1)-(anim[i]==3))*10 + ay=ay+((anim[i]==2)-(anim[i]==4))*10 + if aendx<0: + aendx=aendx+10 + else: + aendx=aendx+((anim[i-11]==1)-(anim[i-11]==3))*10 + aendy=aendy+((anim[i-11]==2)-(anim[i-11]==4))*10 + fill_rect(aendx,aendy,10,10,(255,255,255)) + fill_rect(ax,ay,10,10,(0,204,0)) +# aback=lastPos(anim,ax,ay) +# if u==26 or u==24: +# fill_rect(ax-1,ay-1,3,1,(0,0,0)) +# fill_rect(ax-1,ay+1,3,1,(0,0,0)) +# fill_rect(aback[0],aback[1],10,10,(0,204,0)) +# elif u==34 or u==25: +# fill_rect(ax-1,ay-1,1,3,(0,0,0)) +# fill_rect(ax+1,ay-1,1,3,(0,0,0)) +# fill_rect(aback[0]-2,aback[1]-2,5,5,(0,204,0)) + sleep(0.05) + fill_rect(ax+5,ay,2,4,(0,0,0)) + fill_rect(ax+5,ay+6,2,4,(0,0,0)) + fill_rect(ax+10,ay+4,4,2,(255,0,0)) + fill_rect(ax+14,ay+2,2,2,(255,0,0)) + fill_rect(ax+14,ay+6,2,2,(255,0,0)) + draw_string("(DELETE to exit)",0,0) + draw_string("> Play <",125,140,oscolor()) + draw_string(" Options ",110,165) + darkMode=0 + Speed=0.05 + power=5 + score=1 + exit=0 + sel=1 + while keydown(KEY_OK)!=True and exit==0: + if keydown(KEY_DOWN) and sel==1: + draw_string(" Play ",125,140) + draw_string("> Options <",110,165,oscolor()) + sel=2 + elif keydown(KEY_UP) and sel==2: + draw_string("> Play <",125,140,oscolor()) + draw_string(" Options ",110,165) + sel=1 + if keydown(KEY_LEFTPARENTHESIS) and keydown(KEY_RIGHTPARENTHESIS): + draw_string("Dark mode enabled !",80,195) + darkMode=1 + if keydown(KEY_BACKSPACE): + exit=1 + sleep(0.1) + if sel==2 and exit!=1: + fill_rect(0,130,300,60,(255,255,255)) + Speed=0.05 + power=5 + score=1 + draw_string("Speed:"+str(Speed),50,140,oscolor(),'white') + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + sel=1 + sleep(0.2) + while keydown(KEY_OK)!=True or sel!=4: + if keydown(KEY_RIGHT): + sel=sel+1 + elif keydown(KEY_DOWN): + sel=sel+2 + elif keydown(KEY_LEFT): + sel=sel-1 + elif keydown(KEY_UP): + sel=sel-2 + if sel<0: + sel=0 + if sel>4: + sel=4 + if sel==1: + draw_string("Speed:"+str(Speed),50,140,oscolor(),'white') + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + Speed=input("Speed:") + redraw() + elif sel==2: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140,oscolor(),'white') + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + power=int(input("Power:+")) + redraw() + elif sel==3: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170,oscolor(),'white') + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + score=int(input("Score:")) + redraw() + elif sel==4: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170,oscolor(),'white') + if (keydown(KEY_LEFTPARENTHESIS) and keydown(KEY_RIGHTPARENTHESIS)) or darkMode==1: + draw_string("Dark mode enabled !",80,195) + darkMode=1 + if keydown(KEY_BACKSPACE): + exit=1 + break + sleep(0.1) + if exit!=1: + if darkMode==1: + launch(1,Speed,power,score) + elif darkMode==0: + launch(0,Speed,power,score) + elif exit==1: + clearDraw() + return +def launch(darkmode=0,speed=0.05,applePower=5,appleScore=1): + bgC=(248,252,248) + borderC=(0,0,0) + snakeC=(0,204,0) + appleC=(248,0,0) + if darkmode==1: + bgC=(0,0,0) + borderC=(0,0,204) + fill_rect(0,0,320,222,bgC) +# fill_rect(315,0,5,222,borderC) +# fill_rect(0,0,5,222,borderC) +# fill_rect(0,0,320,1,(197,52,49)) + fill_rect(0,221,320,1,(0,0,0)) + try: + get_keys() + except: + fill_rect(0,0,320,1,(255,181,49)) + else: + fill_rect(0,0,320,1,(197,52,49)) + snake=[3,3,3,3,3] + x=154 + y=115 + endx=104 + endy=115 + u,v=3,3 + length=5 + applex,appley=newApple(appleC,bgC) + score,touched=0,0 + while touched!=borderC and touched!=snakeC: + if keydown(0) or keydown(1) or keydown(2) or keydown(3): + u=getMove(u) + if keydown(KEY_BACKSPACE): + while keydown(KEY_BACKSPACE): + sleep(0.1) + while keydown(KEY_BACKSPACE)!=True: + sleep(0.1) + while keydown(KEY_BACKSPACE): + sleep(0.1) + snake.append(u) + if x==applex and y==appley: + length=length+float(applePower) + applex,appley=newApple(appleC,bgC) + score=score+int(appleScore) + x=x+((u==3)-(u==0))*10 + y=y+((u==2)-(u==1))*10 + x,y=checkTeleport(x,y) + if length: + length=length-1 + else: + snake.remove(snake[0]) + endx=endx+((v==3)-(v==0))*10 + endy=endy+((v==2)-(v==1))*10 + endx,endy=checkTeleport(endx,endy) + v=snake[0] + fill_rect(endx-4,endy-4,10,10,bgC) + touched=get_pixel(x,y) + if x<0 or x>320 or y<0 or y>220: + touched=borderC + if touched!=appleC and touched!=bgC: + touched=borderC + fill_rect(x-4,y-4,10,10,snakeC) + back=lastPos(snake,x,y) + if u==3 or u==0: + fill_rect(x,y-4,2,4,(0,0,0)) + fill_rect(x,y+2,2,4,(0,0,0)) + fill_rect(back[0]-4,back[1]-4,10,10,snakeC) + elif u==2 or u==1: + fill_rect(x-4,y,4,2,(0,0,0)) + fill_rect(x+2,y,4,2,(0,0,0)) + fill_rect(back[0]-4,back[1]-4,10,10,snakeC) + sleep(float(speed)) +# EPILEPSY WARNING !!! +# snakeC=(randint(0,255),randint(0,255),randint(0,255)) + while snakeC==appleC or snakeC==bgC: + snakeC=(randint(0,255),randint(0,255),randint(0,255)) + # beau() + if len(snake)==640: + if darkmode==1: + draw_string("You win !",120,100,'white','black') + draw_string("(You reached the max length)",20,120,'white','black') + else: + draw_string("You win !",120,100) + draw_string("(You reached the max length)",20,120) + touched=borderC + if darkmode==1: + draw_string("Score:"+str(score),10,10,'white','black') + draw_string("(OK=play again, DELETE=Menu)",10,30,'white','black') + else: + draw_string("Score:"+str(score),10,10) + draw_string("(OK=play again, DELETE=Menu)",10,30) + choice=0 + while choice==0: + if keydown(KEY_OK): + choice=1 + launch(darkmode,speed,applePower,appleScore) + elif keydown(KEY_BACKSPACE): + choice=2 + menu() + print("Score:",score) +menu() diff --git a/ports/sh/examples/numworks/cg_NW_kand_mandel.py b/ports/sh/examples/numworks/cg_NW_kand_mandel.py new file mode 100644 index 000000000..8148dca9f --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_kand_mandel.py @@ -0,0 +1,27 @@ +# This script draws a Mandelbrot fractal set +# N_iteration: degree of precision +import kandinsky +import ion +import time + +N_iteration = 10 + +for x in range(320): + for y in range(222): +# Compute the mandelbrot sequence for the point c = (c_r, c_i) with start value z = (z_r, z_i) + z = complex(0,0) +# Rescale to fit the drawing screen 320x222 + c = complex(3.5*x/319-2.5, -2.5*y/221+1.25) + i = 0 + while (i < N_iteration) and abs(z) < 2: + i = i + 1 + z = z*z+c +# Choose the color of the dot from the Mandelbrot sequence + rgb = int(255*i/N_iteration) + col = kandinsky.color(int(rgb),int(rgb*0.75),int(rgb*0.25)) +# Draw a pixel colored in 'col' at position (x,y) + kandinsky.set_pixel(x,y,col) + +while not ion.keydown(ion.KEY_EXE): + time.sleep(0.1) + diff --git a/ports/sh/examples/numworks/cg_NW_kand_test.py b/ports/sh/examples/numworks/cg_NW_kand_test.py new file mode 100644 index 000000000..8b2c9681c --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_kand_test.py @@ -0,0 +1,46 @@ +from kandinsky import * +from gint import * + +draw_string( "Hello Kandinsky", 10, 10, "white", "red" ) + +draw_string( "Hello Kandinsky", 10, 200, "k" ) + +fill_rect( 25, 25, 100, 100, 00000 ) +fill_rect( 60, 25, 10, 100, 65000 ) +fill_rect( 25, 60, 100, 10, 00031 ) + +fill_rect( 100, 100, 25, 25, "green" ) + +fill_rect( 200, 100, 25, 25, (255,255,0) ) + +fill_rect( 200, 50, 25, 25, (128,0,255) ) + +set_pixel( 150, 150, "red" ) +set_pixel( 160, 160, (0,0,255) ) + + +# The following functions are only valid on fxCG (this is an extension of Kandinsky to take benefit of wide screen + +color = "black" + +if CGEXT_Is_Wide_Screen_Enabled() : + color = "red" +fill_rect( -100, 150, 500, 10, color ) + +CGEXT_Enable_Wide_Screen() + +if CGEXT_Is_Wide_Screen_Enabled() : + color = "green" +else : + color = "purple" +fill_rect( -100, 165, 500, 10, color ) + +CGEXT_Disable_Wide_Screen() + +if CGEXT_Is_Wide_Screen_Enabled() : + color = "blue" +else : + color = "red" +fill_rect( -100, 180, 500, 10, color ) + +getkey() diff --git a/ports/sh/examples/numworks/cg_NW_pacman.py b/ports/sh/examples/numworks/cg_NW_pacman.py new file mode 100644 index 000000000..8b7e422b9 --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_pacman.py @@ -0,0 +1,227 @@ +# PacMan par Kevin FEDYNA +# https://nsi.xyz/numapps/pac-man-en-python-numworks/ +# converti sur fxCG50 et PythonExtra par SlyVTT + +from kandinsky import fill_rect, draw_string +from ion import keydown, KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT +from math import sqrt +from random import randint +from time import monotonic + +try: + from kandinsky import get_keys + color = (192, 53, 53) +except: + color = (255, 183, 52) + +terrain = (262143,131841,187245,187245,131073,186285,135969,252783,249903,251823,1152,251823,249903,251823,131841,187245,147465,219051,135969,195453,131073,262143) +bits = 18 +width = 320 +height = 222 +colors = ((0, 0, 0), (32, 48, 248), (248, 224, 8), tuple(color)) +ghost_color = ((255, 184, 255), (255, 0,0), (255, 184, 82), (0, 255, 255)) +pacgommes = [0,130302,9360,74898,131070,75858,126174,8208,8208,8208,8208,8208,8208,8208,130302,74898,49140,43092,126174,66690,131070,0] +superpacgommes = [0,0,65538,0,0,0,0,0,0,0,0,0,0,0,0,0,65538,0,0,0,0,0,0] +frightened = 0 +lives = 2 +won = 0 +lvl = 0 +score = 0 +chained = 0 + + +class Entity: + def __init__(self, x, y, clr, d=0): + self.x = x + self.y = y + self.d = d + self.nd = d + self.f = 0 + self.out = 0 + self.color = clr + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,self.color) + def espace(self,dx=-1,dy=-1): + if dx == dy: + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[self.nd] + return not terrain[int(self.y + 5.5*dy)]>>(bits-1-int(self.x + 5.5*dx)) & 1 and ((dx != 0 and self.y%1 == 0.5) or (dy != 0 and self.x%1== 0.5)) + def move(self): + global frightened, ghosts, score, chained, lives, total, won + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[self.d] + if self.espace(dx,dy): + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,colors[0]) + self.x = (round(self.x + dx, 1) - 0.5) % 16.5 + 0.5 + self.y = round(self.y + dy, 1) + fill_rect(int(self.x*10)+136,int(self.y*10)-3,8,8,self.color) + if self.color == colors[2]: + if pacgommes[int(self.y)] >> (bits - 1 - int(self.x)) & 1: + pacgommes[int(self.y)] -= 1 << (bits - 1 - int(self.x)) + score += 10 + if superpacgommes[int(self.y)] >> (bits - 1 - int(self.x)) & 1: + superpacgommes[int(self.y)] -= 1 << (bits - 1 - int(self.x)) + score += 50 + chained = 0 + frightened = monotonic() + for g in ghosts: + if g.out: + g.color = colors[1] + g.d = (3, 2, 1, 0)[g.d] + g.f = 1 + for g in range(4): + if sqrt((self.x-ghosts[g].x)**2+(self.y-ghosts[g].y)**2) < 0.6: + if ghosts[g].f: + chained += 1 + total += 1 + score += (1 << chained)*100 + ghosts[g].f = 0 + ghosts[g].color = ghost_color[g] + ghosts[g].x = 9 + ghosts[g].y = 8.5 + if total == 16: + score += 12000 + else: + for gp in range(4): + ghosts[gp].f = 0 + ghosts[gp].color = ghost_color[gp] + ghosts[gp].x = 9 + ghosts[gp].y = 10.5 + ghosts[gp].out = 0 + self.x = 9 + self.y = 16.5 + self.d, self.nd = 0, 0 + lives -= 1 + return render() + if not won and score > 10000: + lives += 1 + won = 1 + px, py = int(self.x - 5.5*dx), int(self.y - 5.5*dy) + if pacgommes[py]>>(bits-1-px) & 1: + fill_rect(px*10+144,py*10+5,2,2,(250, 207, 173)) + if superpacgommes[py]>>(bits-1-px) & 1: + fill_rect(px*10+143,py*10+4,4,4,(250, 207, 173)) + def ia(self,x,y): + if self.f: + while True: + d = randint(0,3) + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[d] + if d != (3,2,1,0)[self.d] and self.espace(dx,dy): + self.d = d + break + else: + distances = [9999 for _ in range(4)] + for i in range(4): + if i != (3,2,1,0)[self.d]: + dx, dy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[i] + if self.espace(dx,dy): + distances[i] = sqrt((self.y + dy - y)**2 + (self.x + dx - x)**2) + self.d = distances.index(min(distances)) + +def prebuild(): + fill_rect(0,0,width,height,colors[0]) + fill_rect(138, 0, 2, height, colors[3]) + draw_string("PAC-MAN", 35, 10, colors[3], colors[0]) + draw_string("nsi.xyz/pacman", 0, 204,colors[0], colors[3]) + draw_string("Score :", 35, 40, (255,)*3, colors[0]) + draw_string("Niveau :", 30, 90, (255,)*3, colors[0]) + +def render(): + global terrain, pacgommes, superpacgommes, lives, arrivee + if lives == -1: + return 42 + draw_string(str(lvl),70-5*len(str(lvl)),110,(255,)*3,colors[0]) + fill_rect(0,150,138,20,colors[0]) + for i in range(lives): + fill_rect(60-(lives-1)*20+i*40,150,20,20,colors[2]) + for l in range(len(terrain)): + for c in range(bits): + fill_rect(c*10+140,l*10+1,10,10,colors[0]) + if pacgommes[l]>>(bits-1-c) & 1: + fill_rect(c*10+144,l*10+5,2,2,(250, 207, 173)) + if superpacgommes[l]>>(bits-1-c) & 1: + fill_rect(c*10+143,l*10+4,4,4,(250, 207, 173)) + if terrain[l]>>(bits-1-c) & 1: + for d in ((1,0),(0,1),(-1,0),(0,-1)): + if 0 <= l + d[0] <= len(terrain) - 1 and 0 <= c + d[1] <= bits - 1 and not terrain[l + d[0]]>>(bits-1-(c+d[1])) & 1: + fill_rect(c*10+140+9*(d[1]==1),l*10+1+9*(d[0]==1),1+9*(d[1]==0),1+9*(d[0]==0),colors[1]) + arrivee = monotonic() + +def engine(): + global frightened, ghosts, pacgommes, superpacgommes, lvl, arrivee, total + while True: + pacgommes = [0,130302,9360,74898,131070,75858,126174,8208,8208,8208,8208,8208,8208,8208,130302,74898,49140,43092,126174,66690,131070,0] + superpacgommes = [0,0,65538,0,0,0,0,0,0,0,0,0,0,0,0,0,65538,0,0,0,0,0,0] + lvl += 1 + total = 0 + render() + pacman = Entity(9, 16.5, colors[2]) + ghosts = [Entity(9, 10.5, ghost_color[i]) for i in range(4)] + while sum(pacgommes) + sum(superpacgommes): + depart = monotonic() + lk=[KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT] + for i in range(4): + if keydown(lk[i]): + if i == (3,2,1,0)[pacman.d]: + pacman.d = i + pacman.nd = i + while monotonic() - depart < 0.01: + if pacman.espace(): + pacman.d = pacman.nd + if pacman.move() == 42: + draw_string("GAME OVER",185,100,colors[3],colors[0]) + return 69 + + draw_string(str(score),70-5*len(str(score)),60,(255,)*3,colors[0]) + + """ Fantomes """ + + if frightened: + if monotonic() - frightened > 6.5: + for g in ghosts: + if g.f: + g.color = (255,)*3 + if monotonic() - frightened > 8.5: + frightened = 0 + for g in range(4): + ghosts[g].color = ghost_color[g] + ghosts[g].f = 0 + + if arrivee: + if monotonic() - arrivee > 0 and not ghosts[1].out: + ghosts[1].out = 1 + ghosts[1].y = 8.5 + if monotonic() - arrivee > 2.5 and not ghosts[0].out: + ghosts[0].out = 1 + ghosts[0].y = 8.5 + if monotonic() - arrivee > 5 and not ghosts[3].out: + ghosts[3].out = 1 + ghosts[3].y = 8.5 + if monotonic() - arrivee > 7.5 and not ghosts[2].out: + ghosts[2].out = 1 + ghosts[2].y = 8.5 + fill_rect(220,101,20,10,colors[0]) + arrivee = 0 + + pdx, pdy = ((-0.1,0),(0,-0.1),(0,0.1),(0.1,0))[pacman.d] + + # Pinky + ghosts[0].ia(pacman.x + 20 * pdx, pacman.y + 20 * pdy) + ghosts[0].move() + + # Inky + ghosts[3].ia(max(min(ghosts[1].x + 2*(pacman.x + 20 * pdx - ghosts[1].x), 16.5), 1.5), max(min(ghosts[1].y +2*(pacman.y + 20 * pdy - ghosts[1].y), 21.5), 1.5)) + ghosts[3].move() + + # Blinky + ghosts[1].ia(pacman.x, pacman.y) + ghosts[1].move() + + # Clyde + if sqrt((ghosts[2].x - pacman.x)**2 + (ghosts[2].y - pacman.y)**2) > 4: + ghosts[2].ia(pacman.x, pacman.y) + else: + ghosts[2].ia(1.5, 20.5) + ghosts[2].move() + + +fill_rect(0,0,319,219,"black") +prebuild() +engine() diff --git a/ports/sh/examples/numworks/cg_NW_rosace.py b/ports/sh/examples/numworks/cg_NW_rosace.py new file mode 100644 index 000000000..42e6b4aa9 --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_rosace.py @@ -0,0 +1,77 @@ +from kandinsky import * +from math import * +import ion +import time + +def cercle1(x0,y0,r,c,e): + for i in range(2*e): + xd=x0-int((r-i*0.5)/sqrt(2)) + xf=x0+int((r-i*0.5)/sqrt(2)) + for x in range(xd,xf+1): + x1=x + y1=y0+int(sqrt((r-i*0.5)**2-(x-x0)**2)) + if sqrt((160-x1)**2+(111-y1)**2)n-4:col=c2 + else:col=c1 + cercle2(x1,y1,rj,col,e) + + +col1=color(5,50,120) +col2=color(255,45,45) +col3=color(245,225,25) +#rosace1(12,50,col1,2) +#rosace2(12,50,col1,1) +rosace3(10,55,col1,col2,col3,1) + +while not ion.keydown(ion.KEY_EXE): + time.sleep(0.1) \ No newline at end of file diff --git a/ports/sh/examples/numworks/cg_NW_snake.py b/ports/sh/examples/numworks/cg_NW_snake.py new file mode 100644 index 000000000..a498aa897 --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_snake.py @@ -0,0 +1,326 @@ +# Snake from Golem64 +# https://my.numworks.com/python/golem64/snake +# +# converted to PythonExtra on fx-CG50 by SlyVTT +# +# Version 1.7 STABLE +# Tip: You should try to press +# some keys in the menu... + +from random import * +from kandinsky import * +from ion import * +from time import * + +def oscolor(): + try: + get_keys() + except: + return 'orange' + else: + return 'red' + +def lastPos(i,x,y): + if i[-1]==3: + pos=[x-10,y] + elif i[-1]==2: + pos=[x,y-10] + elif i[-1]==0: + pos=[x+10,y] + elif i[-1]==1: + pos=[x,y+10] + pos[0],pos[1]=checkTeleport(pos[0],pos[1]) + return pos + +def newApple(appleC,bgC): + applex=randint(0,31)*10+4 + appley=randint(0,21)*10+5 + while get_pixel(applex,appley)!=bgC: + applex=randint(0,31)*10+4 + appley=randint(0,21)*10+5 + fill_rect(applex-4,appley-4,10,10,appleC) + return applex,appley + +def checkTeleport(x,y): + if x<4: + x=314 + if x>314: + x=4 + if y<5: + y=215 + if y>215: + y=5 + return x,y + +def getMove(u): + lk=[KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT] + for k in range(4): + if keydown(lk[k])==True and u+k!=3: return k + return u + +def clearDraw(): + fill_rect(0,0,320,222,(255,255,255)) + +def clearHome(): + print("\n \n \n \n \n \n \n \n \n \n \n \n \n ") + +def redraw(): + draw_string("(DELETE to exit)",0,0) + printLetter([1,1,1,1,0,0,1,1,1,0,0,1,1,1,1],70,80,10,(0,204,0)) + fill_rect(95,80,2,4,(0,0,0)) + fill_rect(95,86,2,4,(0,0,0)) + fill_rect(100,84,4,2,(255,0,0)) + fill_rect(104,82,2,2,(255,0,0)) + fill_rect(104,86,2,2,(255,0,0)) + printLetter([1,1,1,1,0,1,1,0,1,1,0,1,1,0,1],110,80,10,(0,0,0)) + printLetter([1,1,1,1,0,1,1,1,1,1,0,1,1,0,1],150,80,10,(0,0,0)) + printLetter([1,0,1,1,0,1,1,1,0,1,0,1,1,0,1],190,80,10,(0,0,0)) + printLetter([1,1,1,1,0,0,1,1,1,1,0,0,1,1,1],230,80,10,(0,0,0)) + +def printLetter(letter,x,y,size,color): + for yi in range(5): + for xi in range(3): + if letter[yi*3+xi]==1: + fill_rect(x+(xi*size),y+(yi*size),size,size,color) + +def menu(): + clearDraw() + printLetter([1,1,1,1,0,1,1,0,1,1,0,1,1,0,1],110,80,10,(0,0,0)) + printLetter([1,1,1,1,0,1,1,1,1,1,0,1,1,0,1],150,80,10,(0,0,0)) + printLetter([1,0,1,1,0,1,1,1,0,1,0,1,1,0,1],190,80,10,(0,0,0)) + printLetter([1,1,1,1,0,0,1,1,1,1,0,0,1,1,1],230,80,10,(0,0,0)) + anim=[1,1,1,1,1,1,1,1,1,4,4,3,3,4,4,1,1] + ax=0 + ay=120 + aendx=-110 + aendy=120 + u=1 + aback=0 + for i in range(len(anim)): + ax=ax+((anim[i]==1)-(anim[i]==3))*10 + ay=ay+((anim[i]==2)-(anim[i]==4))*10 + if aendx<0: + aendx=aendx+10 + else: + aendx=aendx+((anim[i-11]==1)-(anim[i-11]==3))*10 + aendy=aendy+((anim[i-11]==2)-(anim[i-11]==4))*10 + fill_rect(aendx,aendy,10,10,(255,255,255)) + fill_rect(ax,ay,10,10,(0,204,0)) +# aback=lastPos(anim,ax,ay) +# if u==26 or u==24: +# fill_rect(ax-1,ay-1,3,1,(0,0,0)) +# fill_rect(ax-1,ay+1,3,1,(0,0,0)) +# fill_rect(aback[0],aback[1],10,10,(0,204,0)) +# elif u==34 or u==25: +# fill_rect(ax-1,ay-1,1,3,(0,0,0)) +# fill_rect(ax+1,ay-1,1,3,(0,0,0)) +# fill_rect(aback[0]-2,aback[1]-2,5,5,(0,204,0)) + sleep(0.05) + fill_rect(ax+5,ay,2,4,(0,0,0)) + fill_rect(ax+5,ay+6,2,4,(0,0,0)) + fill_rect(ax+10,ay+4,4,2,(255,0,0)) + fill_rect(ax+14,ay+2,2,2,(255,0,0)) + fill_rect(ax+14,ay+6,2,2,(255,0,0)) + draw_string("(DELETE to exit)",0,0) + draw_string("> Play <",125,140,oscolor()) + draw_string(" Options ",110,165) + darkMode=0 + Speed=0.05 + power=5 + score=1 + exit=0 + sel=1 + while keydown(KEY_OK)!=True and exit==0: + if keydown(KEY_DOWN) and sel==1: + draw_string(" Play ",125,140) + draw_string("> Options <",110,165,oscolor()) + sel=2 + elif keydown(KEY_UP) and sel==2: + draw_string("> Play <",125,140,oscolor()) + draw_string(" Options ",110,165) + sel=1 + if keydown(KEY_LEFTPARENTHESIS) and keydown(KEY_RIGHTPARENTHESIS): + draw_string("Dark mode enabled !",80,195) + darkMode=1 + if keydown(KEY_BACKSPACE): + exit=1 + sleep(0.1) + if sel==2 and exit!=1: + fill_rect(0,130,300,60,(255,255,255)) + Speed=0.05 + power=5 + score=1 + draw_string("Speed:"+str(Speed),50,140,oscolor(),'white') + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + sel=1 + sleep(0.2) + while keydown(KEY_OK)!=True or sel!=4: + if keydown(KEY_RIGHT): + sel=sel+1 + elif keydown(KEY_DOWN): + sel=sel+2 + elif keydown(KEY_LEFT): + sel=sel-1 + elif keydown(KEY_UP): + sel=sel-2 + if sel<0: + sel=0 + if sel>4: + sel=4 + if sel==1: + draw_string("Speed:"+str(Speed),50,140,oscolor(),'white') + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + Speed=input("Speed:") + redraw() + elif sel==2: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140,oscolor(),'white') + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + power=int(input("Power:+")) + redraw() + elif sel==3: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170,oscolor(),'white') + draw_string("Play",220,170) + if keydown(KEY_OK): + clearHome() + score=int(input("Score:")) + redraw() + elif sel==4: + draw_string("Speed:"+str(Speed),50,140) + draw_string("Power:+"+str(power),200,140) + draw_string("Score:+"+str(score),50,170) + draw_string("Play",220,170,oscolor(),'white') + if (keydown(KEY_LEFTPARENTHESIS) and keydown(KEY_RIGHTPARENTHESIS)) or darkMode==1: + draw_string("Dark mode enabled !",80,195) + darkMode=1 + if keydown(KEY_BACKSPACE): + exit=1 + break + sleep(0.1) + if exit!=1: + if darkMode==1: + launch(1,Speed,power,score) + elif darkMode==0: + launch(0,Speed,power,score) + elif exit==1: + clearDraw() + return + +def launch(darkmode=0,speed=0.05,applePower=5,appleScore=1): + bgC=(248,252,248) + borderC=(0,0,0) + snakeC=(0,204,0) + appleC=(248,0,0) + if darkmode==1: + bgC=(0,0,0) + borderC=(0,0,204) + fill_rect(0,0,320,222,bgC) +# fill_rect(315,0,5,222,borderC) +# fill_rect(0,0,5,222,borderC) +# fill_rect(0,0,320,1,(197,52,49)) + fill_rect(0,221,320,1,(0,0,0)) + try: + get_keys() + except: + fill_rect(0,0,320,1,(255,181,49)) + else: + fill_rect(0,0,320,1,(197,52,49)) + snake=[3,3,3,3,3] + x=154 + y=115 + endx=104 + endy=115 + u,v=3,3 + length=5 + applex,appley=newApple(appleC,bgC) + score,touched=0,0 + while touched!=borderC and touched!=snakeC: + if keydown(KEY_LEFT) or keydown(KEY_UP) or keydown(KEY_DOWN) or keydown(KEY_RIGHT): + u=getMove(u) + if keydown(KEY_BACKSPACE): + while keydown(KEY_BACKSPACE): + sleep(0.1) + while keydown(KEY_BACKSPACE)!=True: + sleep(0.1) + while keydown(KEY_BACKSPACE): + sleep(0.1) + snake.append(u) + if x==applex and y==appley: + length=length+float(applePower) + applex,appley=newApple(appleC,bgC) + score=score+int(appleScore) + x=x+((u==3)-(u==0))*10 + y=y+((u==2)-(u==1))*10 + x,y=checkTeleport(x,y) + if length: + length=length-1 + else: + snake.remove(snake[0]) + endx=endx+((v==3)-(v==0))*10 + endy=endy+((v==2)-(v==1))*10 + endx,endy=checkTeleport(endx,endy) + v=snake[0] + fill_rect(endx-4,endy-4,10,10,bgC) + touched=get_pixel(x,y) + if x<0 or x>320 or y<0 or y>220: + touched=borderC + if touched!=appleC and touched!=bgC: + touched=borderC + fill_rect(x-4,y-4,10,10,snakeC) + back=lastPos(snake,x,y) + if u==3 or u==0: + fill_rect(x,y-4,2,4,(0,0,0)) + fill_rect(x,y+2,2,4,(0,0,0)) + fill_rect(back[0]-4,back[1]-4,10,10,snakeC) + elif u==2 or u==1: + fill_rect(x-4,y,4,2,(0,0,0)) + fill_rect(x+2,y,4,2,(0,0,0)) + fill_rect(back[0]-4,back[1]-4,10,10,snakeC) + sleep(float(speed)) +# EPILEPSY WARNING !!! +# snakeC=(randint(0,255),randint(0,255),randint(0,255)) + while snakeC==appleC or snakeC==bgC: + snakeC=(randint(0,255),randint(0,255),randint(0,255)) + # beau() + if len(snake)==640: + if darkmode==1: + draw_string("You win !",120,100,'white','black') + draw_string("(You reached the max length)",20,120,'white','black') + else: + draw_string("You win !",120,100) + draw_string("(You reached the max length)",20,120) + touched=borderC + if darkmode==1: + draw_string("Score:"+str(score),10,10,'white','black') + draw_string("(OK=play again, DELETE=Menu)",10,30,'white','black') + else: + draw_string("Score:"+str(score),10,10) + draw_string("(OK=play again, DELETE=Menu)",10,30) + choice=0 + while choice==0: + if keydown(KEY_OK): + choice=1 + launch(darkmode,speed,applePower,appleScore) + elif keydown(KEY_BACKSPACE): + choice=2 + menu() + print("Score:",score) + + +try: + CGEXT_Set_Margin_Color( "black" ) +except: + print("fxCG Extension not supported") + +menu() diff --git a/ports/sh/examples/numworks/cg_NW_time_test.py b/ports/sh/examples/numworks/cg_NW_time_test.py new file mode 100644 index 000000000..e94b85850 --- /dev/null +++ b/ports/sh/examples/numworks/cg_NW_time_test.py @@ -0,0 +1,15 @@ +from time import * + +print(monotonic()) + +sleep(1) + +print(monotonic()) + +sleep(2) + +print(monotonic()) + +sleep(1) + +print(monotonic()) diff --git a/ports/sh/main.c b/ports/sh/main.c index e80167d2f..be17e8218 100644 --- a/ports/sh/main.c +++ b/ports/sh/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,14 @@ widget_shell *pe_shell; struct pe_globals PE = { 0 }; + +// TODO : make this more clean by putting these globals into pe_globals and +// making this accessible to modules +bool is_dwindowed = false; +bool is_timered = false; +unsigned int timer_altered[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +bool is_refreshed_required = false; + //=== Hook for redirecting stdout/stderr to the shell ===// static ssize_t stdouterr_write(void *data, void const *buf, size_t size) @@ -170,6 +179,15 @@ void pe_enter_graphics_mode(void) PE.shell->widget.update = 0; } +void pe_refresh_graphics(void) +{ + /* refresh graphical output on request by setting + is_refresh_graphics to true */ + dupdate(); + pe_debug_run_videocapture(); + is_refreshed_required = false; +} + void pe_draw(void) { dclear(C_WHITE); @@ -194,6 +212,31 @@ void pe_draw(void) //=== Application control functions ===// +void pe_restore_window_and_timer(void) +{ + if (is_dwindowed) + { + struct dwindow win; + win.left = 0; + win.top = 0; + win.right = DWIDTH; + win.bottom = DHEIGHT; + + dwindow_set(win); + + is_dwindowed = false; // we mark as not windowed + } + + if (is_timered) + { + for (int u = 0; u < 9; u++) + if (timer_altered[u] == 1) + timer_stop(u); + + is_timered = false; + } +} + static void pe_reset_micropython(void) { gc_sweep_all(); @@ -296,6 +339,8 @@ static char *pe_handle_event(jevent e, bool shell_bound) } free(module); + pe_restore_window_and_timer(); + pe_print_prompt(1); } } @@ -425,6 +470,13 @@ int main(int argc, char **argv) - The OS' extra VRAM - Memory past the 2 MB boundary on tested OSes */ // gc_add(start, end)... + + /* TODO : test to check if we can definitely maintain this addition of RAM */ + + void *uram_area = kmalloc(300000, "_uram"); + if(uram_area) + gc_add(uram_area, uram_area+300000); + #endif mp_init(); @@ -496,6 +548,8 @@ int main(int argc, char **argv) //=== Deinitialization ===// + pe_debug_close(); + gc_sweep_all(); mp_deinit(); console_destroy(PE.console); diff --git a/ports/sh/mpconfigport.h b/ports/sh/mpconfigport.h index 761a1b509..4d2058993 100644 --- a/ports/sh/mpconfigport.h +++ b/ports/sh/mpconfigport.h @@ -107,8 +107,11 @@ void pe_after_python_exec( /* Command executed regularly during execution */ extern void pe_draw(void); extern widget_shell *pe_shell; +extern void pe_refresh_graphics(void); +extern bool is_refreshed_required; #define MICROPY_VM_HOOK_LOOP \ - { if(pe_shell->widget.update) pe_draw(); } + { if(pe_shell->widget.update) pe_draw(); \ + if(is_refreshed_required) pe_refresh_graphics(); } /* extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ @@ -123,3 +126,4 @@ typedef long mp_off_t; #define MICROPY_HW_MCU_NAME "sh-4a" #define MP_STATE_PORT MP_STATE_VM + diff --git a/ports/sh/numworks/ion.c b/ports/sh/numworks/ion.c new file mode 100644 index 000000000..8cf09bd9d --- /dev/null +++ b/ports/sh/numworks/ion.c @@ -0,0 +1,204 @@ +//---------------------------------------------------------------------------// +// ____ PythonExtra // +//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. // +//.-'` `---` ' License: MIT (except some files; see LICENSE) // +//---------------------------------------------------------------------------// +// pe.ion: `gint` module +// +// This module aims to wrap commonly-used gint functions (not all APIs are +// considered relevant for high-level Python development). +//--- + +#include "console.h" +#include "py/objtuple.h" +#include "py/runtime.h" +#include + +#include +#include + +/* BEGINING OF KEY TRANSLATION */ + +// the following table aims at providing a keymap for NW on Casio +// line that are commented correspond to keys that are similar (with exact same +// name) between NW and Casio + +#define KEY_LEFT 0 +#define KEY_UP 1 +#define KEY_DOWN 2 +#define KEY_RIGHT 3 +#define KEY_OK 4 +#define KEY_BACK 5 +#define KEY_HOME 6 +#define KEY_ONOFF 7 +/* -- */ +#define KEY_SHIFT 12 +#define KEY_ALPHA 13 +#define KEY_XNT 14 +#define KEY_VAR 15 +#define KEY_TOOLBOX 16 +#define KEY_BACKSPACE 17 +#define KEY_EXP 18 +#define KEY_LN 19 +#define KEY_LOG 20 +#define KEY_IMAGINARY 21 +#define KEY_COMMA 22 +#define KEY_POWER 23 +#define KEY_SINE 24 +#define KEY_COSINE 25 +#define KEY_TANGENT 26 +#define KEY_PI 27 +#define KEY_SQRT 28 +#define KEY_SQUARE 29 +#define KEY_SEVEN 30 +#define KEY_EIGHT 31 +#define KEY_NINE 32 +#define KEY_LEFTPARENTHESIS 33 +#define KEY_RIGHTPARENTHESIS 34 +/* -- */ +#define KEY_FOUR 36 +#define KEY_FIVE 37 +#define KEY_SIX 38 +#define KEY_MULTIPLICATION 39 +#define KEY_DIVISION 40 +/* -- */ +#define KEY_ONE 42 +#define KEY_TWO 43 +#define KEY_THREE 44 +#define KEY_PLUS 45 +#define KEY_MINUS 46 +/* -- */ +#define KEY_ZERO 48 +#define KEY_DOT 49 +#define KEY_EE 50 +#define KEY_ANS 51 +#define KEY_EXE 52 + +int KeyTranslationMap[ 53 ] = { 0x85, 0x86, 0x75, 0x76, 0x91, // gint LEFT, UP, DOWN, RIGHT, F1 + 0x74, 0x84, 0x07, -1, -1, // gint EXIT, MENU, ACON, __, __ + -1, -1, 0x81, 0x71, 0x61, // gint __, __, SHIFT, ALPHA, XOT + 0x83, 0x82, 0x44, 0x13, 0x63, // gint VARS, OPTN, DEL, EXP, LN + 0x62, 0x92, 0x55, 0x73, 0x64, // gint LOG, F2, COMMA, POWER, SIN + 0x65, 0x66, 0x93, 0x94, 0x72, // gint COS, TAN, F3, F4, SQUARE + 0x41, 0x42, 0x43, 0x53, 0x54, // gint 7, 8, 9, LEFP, RIGHTP + -1, 0x31, 0x32, 0x33, 0x34, // gint __, 4, 5, 6, MUL + 0x35, -1, 0x21, 0x22, 0x23, // gint DIV, __, 1, 2, 3 + 0x24, 0x25, -1, 0x11, 0x12, // gint ADD, SUB, __, 0, DOT + 0x95, 0x14, 0x15 }; // gint F5, NEG, EXE + + +/* END OF KEY TRANSLATION */ + + + +#define FUN_0(NAME) MP_DEFINE_CONST_FUN_OBJ_0(ion_##NAME##_obj, ion_##NAME) +#define FUN_1(NAME) MP_DEFINE_CONST_FUN_OBJ_1(ion_##NAME##_obj, ion_##NAME) +#define FUN_2(NAME) MP_DEFINE_CONST_FUN_OBJ_2(ion_##NAME##_obj, ion_##NAME) +#define FUN_3(NAME) MP_DEFINE_CONST_FUN_OBJ_3(ion_##NAME##_obj, ion_##NAME) +#define FUN_VAR(NAME, MIN) \ + MP_DEFINE_CONST_FUN_OBJ_VAR(ion_##NAME##_obj, MIN, ion_##NAME) +#define FUN_BETWEEN(NAME, MIN, MAX) \ + MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ion_##NAME##_obj, MIN, MAX, ion_##NAME) + +STATIC mp_obj_t ion___init__(void) { return mp_const_none; } + +/* */ + +STATIC mp_obj_t ion_keydown(mp_obj_t arg1) { + mp_int_t key = mp_obj_get_int(arg1); + + if (key < KEY_LEFT || key > KEY_EXE ) + return mp_obj_new_bool(false); + + int translatedKey = KeyTranslationMap[ key ]; + + if (translatedKey==-1) + return mp_obj_new_bool(false); + + clearevents(); + + bool down = keydown(translatedKey) != 0; + return mp_obj_new_bool(down); +} + +FUN_1(keydown); +FUN_0(__init__); + +/* Module definition */ + +// Helper: define object "ion_F_obj" as object "F" in the module +#define OBJ(F) \ + { MP_ROM_QSTR(MP_QSTR_##F), MP_ROM_PTR(&ion_##F##_obj) } + +// Helper: define small integer constant "I" as "I" in the module +#define INT(I) \ + { MP_ROM_QSTR(MP_QSTR_##I), MP_OBJ_NEW_SMALL_INT(I) } + +STATIC const mp_rom_map_elem_t ion_module_globals_table[] = { + {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ion)}, + OBJ(__init__), + + /*Numworks keycodes */ + /* BE CAREFUL THERE ARE MISSING SLOTS */ + + INT(KEY_LEFT), // value 0 + INT(KEY_UP), + INT(KEY_DOWN), + INT(KEY_RIGHT), + INT(KEY_OK), + INT(KEY_BACK), + INT(KEY_HOME), + INT(KEY_ONOFF), // value 7 + + INT(KEY_SHIFT), // value 12 + INT(KEY_ALPHA), + INT(KEY_XNT), + INT(KEY_VAR), + INT(KEY_TOOLBOX), + INT(KEY_BACKSPACE), + INT(KEY_EXP), + INT(KEY_LN), + INT(KEY_LOG), + INT(KEY_IMAGINARY), + INT(KEY_COMMA), + INT(KEY_POWER), + INT(KEY_SINE), + INT(KEY_COSINE), + INT(KEY_TANGENT), + INT(KEY_PI), + INT(KEY_SQRT), + INT(KEY_SQUARE), + INT(KEY_SEVEN), + INT(KEY_EIGHT), + INT(KEY_NINE), + INT(KEY_LEFTPARENTHESIS), + INT(KEY_RIGHTPARENTHESIS), // value 34 + + INT(KEY_FOUR), // value 36 + INT(KEY_FIVE), + INT(KEY_SIX), + INT(KEY_MULTIPLICATION), + INT(KEY_DIVISION), // value 40 + + INT(KEY_ONE), // value 42 + INT(KEY_TWO), + INT(KEY_THREE), + INT(KEY_PLUS), + INT(KEY_MINUS), // value 46 + + INT(KEY_ZERO), // value 48 + INT(KEY_DOT), + INT(KEY_EE), + INT(KEY_ANS), + INT(KEY_EXE), // value 52 + + OBJ(keydown), +}; +STATIC MP_DEFINE_CONST_DICT(ion_module_globals, ion_module_globals_table); + +const mp_obj_module_t ion_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&ion_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_ion, ion_module); diff --git a/ports/sh/numworks/modkandinsky.c b/ports/sh/numworks/modkandinsky.c new file mode 100644 index 000000000..169745ad9 --- /dev/null +++ b/ports/sh/numworks/modkandinsky.c @@ -0,0 +1,341 @@ +//---------------------------------------------------------------------------// +// ____ PythonExtra // +//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. // +//.-'` `---` ' License: MIT (except some files; see LICENSE) // +//---------------------------------------------------------------------------// +// pe.modkandinsky: Compatibility module for NumWorks Kandinsky library + +#include "py/obj.h" +#include "py/runtime.h" +#include +#include +#include + +#include +#include + +extern font_t numworks; + +extern bool is_dwindowed; +extern bool is_timered; +extern unsigned int timer_altered[9]; +extern bool is_refreshed_required; + +#define NW_MAX_X 320 +#define NW_MAX_Y 222 + +/* Parameters used in windowed mode to center the screen of the NW in the fxCG screen*/ +#define DELTAXNW ((DWIDTH - NW_MAX_X) / 2) // we center the NW screen on Casio's screen +#define DELTAYNW ((DHEIGHT - NW_MAX_Y) / 2) + +/* refresh rate of the screen */ +#define TARGET_FPS 20 + +/* Definition of color on Numworks */ + +// Data can be found here +// https://github.com/numworks/epsilon/blob/master/escher/include/escher/palette.h +// and here +// https://github.com/numworks/epsilon/blob/master/python/port/port.cpp#L221 + +#define NW_RGB(r, g, b) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)) + +#define NW_BLUE NW_RGB(0x50, 0x75, 0xF2) +#define NW_RED NW_RGB(0xFF, 0x00, 0x0C) +#define NW_GREEN NW_RGB(0x50, 0xC1, 0x02) +#define NW_WHITE NW_RGB(0xFF, 0xFF, 0xFF) +#define NW_BLACK NW_RGB(0x00, 0x00, 0x00) + +#define NW_YELLOW NW_RGB(0xFF, 0xCC, 0x7B) +#define NW_PURPLE NW_RGB(0x6E, 0x2D, 0x79) +#define NW_BROWN NW_RGB(0x8D, 0x73, 0x50) +#define NW_CYAN NW_RGB(0x00, 0xFF, 0xFF) +#define NW_ORANGE NW_RGB(0xFE, 0x87, 0x1F) +#define NW_PINK NW_RGB(0xFF, 0xAB, 0xB6) +#define NW_MAGENTA NW_RGB(0xFF, 0x05, 0x88) +#define NW_GRAY NW_RGB(0xA7, 0xA7, 0xA7) + +// There are possibly some others to be listed correctly + +static int callback(void) { + is_refreshed_required = true; + return TIMER_CONTINUE; +} + +static mp_obj_t Kandinsky_make_color(color_t color) { + int r, g, b; + r = (color >> 8) & 0xf8; + g = (color >> 3) & 0xfc; + b = (color << 3) & 0xfc; + + mp_obj_t items[3] = { + MP_OBJ_NEW_SMALL_INT(r), + MP_OBJ_NEW_SMALL_INT(g), + MP_OBJ_NEW_SMALL_INT(b), + }; + return mp_obj_new_tuple(3, items); +} + +static mp_obj_t Kandinsky_init(void) { + void pe_enter_graphics_mode(void); + pe_enter_graphics_mode(); + + dclear(NW_WHITE); + + struct dwindow nw; + nw.left = DELTAXNW; + nw.top = DELTAYNW; + nw.right = 320 + DELTAXNW; + nw.bottom = 222 + DELTAYNW; + dwindow_set(nw); + is_dwindowed = true; // we mark as windowed + + int t = timer_configure(TIMER_TMU, (1000000/TARGET_FPS), GINT_CALL(callback)); + if (t >= 0) { + timer_start(t); + is_timered = true; // there is a timer altered from this module + timer_altered[t] = 1; // we put the corresponding timer at 1 to identify it + } + return mp_const_none; +} + +static mp_obj_t Kandinsky_color(size_t n, mp_obj_t const *args) { + int r = mp_obj_get_int(args[0]); + int g = mp_obj_get_int(args[1]); + int b = mp_obj_get_int(args[2]); + int color = NW_RGB(r, g, b); + + return mp_obj_new_int(color); +} + +int Internal_Get_Color_From_String(const char *str) { + + if (strcmp(str, "red") == 0 || strcmp(str, "r") == 0) + return NW_RED; + else if (strcmp(str, "green") == 0 || strcmp(str, "g") == 0) + return NW_GREEN; + else if (strcmp(str, "blue") == 0 || strcmp(str, "b") == 0) + return NW_BLUE; + else if (strcmp(str, "black") == 0 || strcmp(str, "k") == 0) + return NW_BLACK; + else if (strcmp(str, "white") == 0 || strcmp(str, "w") == 0) + return NW_WHITE; + + else if (strcmp(str, "yellow") == 0 || strcmp(str, "y") == 0) + return NW_YELLOW; + else if (strcmp(str, "pink") == 0) + return NW_PINK; + else if (strcmp(str, "magenta") == 0) + return NW_MAGENTA; + else if (strcmp(str, "grey") == 0 || strcmp(str, "gray") == 0) + return NW_GRAY; + else if (strcmp(str, "purple") == 0) + return NW_PURPLE; + else if (strcmp(str, "orange") == 0) + return NW_ORANGE; + else if (strcmp(str, "cyan") == 0) + return NW_CYAN; + else if (strcmp(str, "brown") == 0) + return NW_BROWN; + else + return C_NONE; +} + +int Internal_Treat_Color(mp_obj_t color) { + const mp_obj_type_t *type = mp_obj_get_type(color); + + if (type == &mp_type_str) { + size_t text_len; + char const *text = mp_obj_str_get_data(color, &text_len); + return Internal_Get_Color_From_String(text); + } + + else if (type == &mp_type_int) + return mp_obj_get_int(color); + + else if (type == &mp_type_tuple) { + size_t tuple_len; + mp_obj_t *items; + mp_obj_tuple_get(color, &tuple_len, &items); + int r = mp_obj_get_int(items[0]); + int g = mp_obj_get_int(items[1]); + int b = mp_obj_get_int(items[2]); + return NW_RGB(r, g, b); + } else + return NW_BLACK; +} + +static mp_obj_t Kandinsky_fill_rect(size_t n, mp_obj_t const *args) { + int x = mp_obj_get_int(args[0]) + DELTAXNW; + int y = mp_obj_get_int(args[1]) + DELTAYNW; + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + + int color = Internal_Treat_Color(args[4]); + + drect(x, y, x + w - 1, y + h - 1, color); + + return mp_const_none; +} + +static mp_obj_t Kandinsky_set_pixel(size_t n, mp_obj_t const *args) { + int x = mp_obj_get_int(args[0]) + DELTAXNW; + int y = mp_obj_get_int(args[1]) + DELTAYNW; + + int color; + if (n == 3) + color = Internal_Treat_Color(args[2]); + else + color = NW_BLACK; + + dpixel(x, y, color); + return mp_const_none; +} + +static mp_obj_t Kandinsky_get_pixel(mp_obj_t _x, mp_obj_t _y) { + int x = mp_obj_get_int(_x) + DELTAXNW; + int y = mp_obj_get_int(_y) + DELTAYNW; + + if ((!is_dwindowed && x >= 0 && x < DWIDTH && y >= 0 && y < DHEIGHT) || (is_dwindowed && x >= 0 && x < NW_MAX_X && y >= 0 && y < NW_MAX_Y)) { + color_t color = gint_vram[DWIDTH * y + x]; + return Kandinsky_make_color(color); + } + return Kandinsky_make_color(0x0000); +} + +static mp_obj_t Kandinsky_draw_string(size_t n, mp_obj_t const *args) { + int x = mp_obj_get_int(args[1]) + DELTAXNW + 1; // values used to adjust the visual result as per actual NW + int y = mp_obj_get_int(args[2]) + DELTAYNW + 2; // values used to adjust the visual result as per actual NW + size_t text_len; + char const *text = mp_obj_str_get_data(args[0], &text_len); + + color_t colortext = NW_BLACK; + if (n >= 4) { + colortext = Internal_Treat_Color(args[3]); + } + + color_t colorback = C_NONE; + if (n >= 5) { + colorback = Internal_Treat_Color(args[4]); + } + + font_t const *old_font = dfont(&numworks); + + int u = 0; + int v = 0; + for (int l = 0; l < (int)text_len; l++) { + if (text[l] == '\n') { + u = 0; + v += 16; + } else { + /* The following test is for support of unicode characters that are encoded on 1 char or more */ + /* we need to pass multiple chars to dtext to take care of unicode encoding */ + if(((unsigned char) text[l]) >= 0x00 && ((unsigned char) text[l]) <= 0x7F){ + drect(x + u - 1, y + v - 1, x + u + 9, y + v + 15, colorback); + dtext_opt(x + u, y + v, colortext, C_NONE, DTEXT_LEFT, DTEXT_TOP, &text[l], 1); + u += 10; + } + else if(((unsigned char) text[l]) >= 0x80 && ((unsigned char) text[l]) <= 0xDF){ + drect(x + u - 1, y + v - 1, x + u + 9, y + v + 15, colorback); + dtext_opt(x + u, y + v, colortext, C_NONE, DTEXT_LEFT, DTEXT_TOP, &text[l], 2); + u += 10; + l+=1; + } + else if(((unsigned char) text[l]) >= 0xE0 && ((unsigned char) text[l]) <= 0xEF){ + drect(x + u - 1, y + v - 1, x + u + 9, y + v + 15, colorback); + dtext_opt(x + u, y + v, colortext, C_NONE, DTEXT_LEFT, DTEXT_TOP, &text[l], 3); + u += 10; + l+=2; + } + else if(((unsigned char) text[l]) >= 0xF0 && ((unsigned char) text[l]) <= 0xF7){ + drect(x + u - 1, y + v - 1, x + u + 9, y + v + 15, colorback); + dtext_opt(x + u, y + v, colortext, C_NONE, DTEXT_LEFT, DTEXT_TOP, &text[l], 4); + u += 10; + l+=3; + } + } + } + + dfont(old_font); + + return mp_const_none; +} + +static mp_obj_t Kandinsky_CGEXT_Enable_Wide_Screen( void ) { + + struct dwindow nw; + nw.left = 0; + nw.top = 0; + nw.right = DWIDTH; + nw.bottom = DHEIGHT; + dwindow_set(nw); + is_dwindowed = false; // we mark as not windowed + + return mp_const_none; +} + +static mp_obj_t Kandinsky_CGEXT_Disable_Wide_Screen( void ) { + + struct dwindow nw; + nw.left = DELTAXNW; + nw.top = DELTAYNW; + nw.right = 320 + DELTAXNW; + nw.bottom = 222 + DELTAYNW; + dwindow_set(nw); + is_dwindowed = true; // we mark as windowed + + return mp_const_none; +} + +static mp_obj_t Kandinsky_CGEXT_Is_Wide_Screen_Enabled( void ) { + + return mp_obj_new_bool( is_dwindowed ); +} + +static mp_obj_t Kandinsky_CGEXT_Set_Margin_Color( mp_obj_t color ) { + + color_t colorside = NW_BLACK; + colorside = Internal_Treat_Color(color); + + Kandinsky_CGEXT_Enable_Wide_Screen(); + dclear(colorside); + Kandinsky_CGEXT_Disable_Wide_Screen(); + + return mp_obj_new_bool( is_dwindowed ); +} + +/* Extension of Kandinsky for fxCG - all names starting with "CGEXT_" */ +MP_DEFINE_CONST_FUN_OBJ_0(Kandinsky_CGEXT_Enable_Wide_Screen_obj, Kandinsky_CGEXT_Enable_Wide_Screen); +MP_DEFINE_CONST_FUN_OBJ_0(Kandinsky_CGEXT_Disable_Wide_Screen_obj, Kandinsky_CGEXT_Disable_Wide_Screen); +MP_DEFINE_CONST_FUN_OBJ_0(Kandinsky_CGEXT_Is_Wide_Screen_Enabled_obj, Kandinsky_CGEXT_Is_Wide_Screen_Enabled); +MP_DEFINE_CONST_FUN_OBJ_1(Kandinsky_CGEXT_Set_Margin_Color_obj, Kandinsky_CGEXT_Set_Margin_Color); +/* Standard Kandinsky function as per Numworks specification */ +MP_DEFINE_CONST_FUN_OBJ_0(Kandinsky_init_obj, Kandinsky_init); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Kandinsky_set_pixel_obj, 3, 3, Kandinsky_set_pixel); +MP_DEFINE_CONST_FUN_OBJ_2(Kandinsky_get_pixel_obj, Kandinsky_get_pixel); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Kandinsky_draw_string_obj, 3, 5, Kandinsky_draw_string); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Kandinsky_fill_rect_obj, 5, 5, Kandinsky_fill_rect); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Kandinsky_color_obj, 3, 3, Kandinsky_color); + +STATIC const mp_rom_map_elem_t kandinsky_module_globals_table[] = { + {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_kandinsky)}, + {MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&Kandinsky_init_obj)}, + {MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&Kandinsky_fill_rect_obj)}, + {MP_ROM_QSTR(MP_QSTR_color), MP_ROM_PTR(&Kandinsky_color_obj)}, + {MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&Kandinsky_set_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(&Kandinsky_get_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&Kandinsky_draw_string_obj)}, + {MP_ROM_QSTR(MP_QSTR_CGEXT_Enable_Wide_Screen), MP_ROM_PTR(&Kandinsky_CGEXT_Enable_Wide_Screen_obj)}, + {MP_ROM_QSTR(MP_QSTR_CGEXT_Disable_Wide_Screen), MP_ROM_PTR(&Kandinsky_CGEXT_Disable_Wide_Screen_obj)}, + {MP_ROM_QSTR(MP_QSTR_CGEXT_Is_Wide_Screen_Enabled), MP_ROM_PTR(&Kandinsky_CGEXT_Is_Wide_Screen_Enabled_obj)}, + {MP_ROM_QSTR(MP_QSTR_CGEXT_Set_Margin_Color), MP_ROM_PTR(&Kandinsky_CGEXT_Set_Margin_Color_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(kandinsky_module_globals, + kandinsky_module_globals_table); + +const mp_obj_module_t kandinsky_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&kandinsky_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_kandinsky, kandinsky_module); diff --git a/ports/sh/numworks/time.c b/ports/sh/numworks/time.c new file mode 100644 index 000000000..debcdd0ec --- /dev/null +++ b/ports/sh/numworks/time.c @@ -0,0 +1,111 @@ +//---------------------------------------------------------------------------// +// ____ PythonExtra // +//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. // +//.-'` `---` ' License: MIT (except some files; see LICENSE) // +//---------------------------------------------------------------------------// +// pe.time: `gint` module +// +// This module aims to wrap commonly-used gint functtimes (not all APIs are +// considered relevant for high-level Python development). +//--- + +#include "console.h" +#include "py/objtuple.h" +#include "py/runtime.h" +#include +#include + +#include +#include +#include + +#define FUN_0(NAME) MP_DEFINE_CONST_FUN_OBJ_0(time_##NAME##_obj, time_##NAME) +#define FUN_1(NAME) MP_DEFINE_CONST_FUN_OBJ_1(time_##NAME##_obj, time_##NAME) +#define FUN_2(NAME) MP_DEFINE_CONST_FUN_OBJ_2(time_##NAME##_obj, time_##NAME) +#define FUN_3(NAME) MP_DEFINE_CONST_FUN_OBJ_3(time_##NAME##_obj, time_##NAME) +#define FUN_VAR(NAME, MIN) \ + MP_DEFINE_CONST_FUN_OBJ_VAR(time_##NAME##_obj, MIN, time_##NAME) +#define FUN_BETWEEN(NAME, MIN, MAX) \ + MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_##NAME##_obj, MIN, MAX, time_##NAME) + + + +extern bool is_timered; +extern unsigned int timer_altered[9]; + +static uint64_t tickmono = 0; + + +static int monotonic_callback(void) { + tickmono++; + return TIMER_CONTINUE; +} + + +STATIC mp_obj_t time___init__(void) +{ + tickmono = 0; + + int t = timer_configure(TIMER_TMU, 1000, GINT_CALL(monotonic_callback)); + if (t >= 0) + { + timer_start(t); + is_timered = true; // there is a timer altered from this module + timer_altered[t] = 1; // we put the corresponding timer at 1 to identify it + } + + return mp_const_none; +} + +/* */ + +STATIC mp_obj_t time_sleep(mp_obj_t arg1) +{ + mp_float_t duration = mp_obj_get_float(arg1); + + uint64_t length = (uint64_t)(duration * 1000000.0f); // duration is in seconds and length in µs + + sleep_us(length); + + return mp_const_none; +} + +STATIC mp_obj_t time_monotonic(void) +{ + float value = (float) ((uint64_t) (tickmono * 1000 +0.5 )) / 1000000.0f; + + return mp_obj_new_float( value ); +} + + + +FUN_1(sleep); +FUN_0(monotonic); +FUN_0(__init__); + + +/* Module definittime */ + +// Helper: define object "time_F_obj" as object "F" in the module +#define OBJ(F) \ + { MP_ROM_QSTR(MP_QSTR_##F), MP_ROM_PTR(&time_##F##_obj) } + +// Helper: define small integer constant "I" as "I" in the module +#define INT(I) \ + { MP_ROM_QSTR(MP_QSTR_##I), MP_OBJ_NEW_SMALL_INT(I) } + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_time)}, + OBJ(__init__), + OBJ(sleep), + OBJ(monotonic), +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t time_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&time_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_time, time_module);