2024-11-11 12:44:51 -06:00
|
|
|
/*
|
|
|
|
User Extensions
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Definitions
|
2024-11-11 14:36:11 -06:00
|
|
|
void SDWriteTwo (File file, uint16_t word) {
|
|
|
|
file.write(word & 0xFF); file.write((word >> 8) & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
object *fn_savescreen (object *args, object *env) {
|
|
|
|
(void) env;
|
|
|
|
#if defined(sdcardsupport)
|
|
|
|
object *arg = checkstring(first(args));
|
2024-11-11 16:27:44 -06:00
|
|
|
SDBegin();
|
2024-11-11 14:36:11 -06:00
|
|
|
File file;
|
|
|
|
char buffer[BUFFERSIZE];
|
|
|
|
file = SD.open(MakeFilename(arg, buffer), FILE_WRITE);
|
|
|
|
if (!file) error2(PSTR("problem saving to SD card or invalid filename"));
|
|
|
|
uint16_t width = 320, height = 240;
|
|
|
|
file.write('B'); file.write('M'); // BMP
|
|
|
|
SDWriteInt(file, 14+40+width*height*2); // File size in bytes
|
|
|
|
SDWriteInt(file, 0);
|
|
|
|
SDWriteInt(file, 14+40); // Offset to image data from start
|
|
|
|
// Image header: 40 bytes
|
|
|
|
SDWriteInt(file, 40); // Header size
|
|
|
|
SDWriteInt(file, width); // Image width
|
|
|
|
SDWriteInt(file, height); // Image height
|
|
|
|
SDWriteTwo(file, 1); // Planes
|
|
|
|
SDWriteTwo(file, 16); // Bits per pixel
|
|
|
|
SDWriteInt(file, 0); // Compression (none)
|
|
|
|
SDWriteInt(file, 0); // Image size (0 for uncompressed)
|
|
|
|
SDWriteInt(file, 0); // Preferred X resolution (ignore)
|
|
|
|
SDWriteInt(file, 0); // Preferred Y resolution (ignore)
|
|
|
|
SDWriteInt(file, 0); // Colour map entries (ignore)
|
|
|
|
SDWriteInt(file, 0); // Important colours (ignore)
|
|
|
|
// Image data: width * height * 2 bytes
|
|
|
|
for (int y=height-1; y>=0; y--) {
|
|
|
|
int line = y/Leading, row = y%Leading;
|
|
|
|
for (int x=0; x<width; x++) {
|
|
|
|
int column = x/6, col = x%6;
|
|
|
|
char c = 0; bool bit;
|
|
|
|
if (column < Columns) c = ScrollBuf[column][(line+Scroll) % Lines];
|
|
|
|
if (col>=5 || row>=8) bit = 0;
|
|
|
|
else bit = font[(c & 0x7f)*5 + col] >> row & 1;
|
|
|
|
uint16_t rgb;
|
|
|
|
if (c & 0x80 && row<8) {
|
|
|
|
if (bit) rgb = COLOR_BLACK; else rgb = COLOR_GREEN;
|
|
|
|
} else {
|
|
|
|
if (bit) rgb = COLOR_WHITE; else rgb = COLOR_BLACK;
|
|
|
|
}
|
|
|
|
uint16_t data = (rgb & 0xFFC0)>>1 | (rgb & 0x1F); // Convert to 555 format
|
|
|
|
SDWriteTwo(file, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
#endif
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-11-22 21:04:31 -06:00
|
|
|
void hyperprint (object *form, int lm, pfun_t pfun) {
|
|
|
|
if (atom(form)) {
|
|
|
|
if (isbuiltin(form, NOTHING)) printsymbol(form, pfun);
|
|
|
|
else printobject(form, pfun);
|
|
|
|
} else if (quoted(form)) {
|
|
|
|
pfun('\'');
|
|
|
|
hyperprint(car(cdr(form)), lm + 1, pfun);
|
|
|
|
} else {
|
|
|
|
lm = lm + PPINDENT;
|
|
|
|
bool fits = (subwidth(form, PPWIDTH - lm - PPINDENT) >= 0);
|
|
|
|
int special = 0, extra = 0; bool separate = true;
|
|
|
|
object *arg = car(form);
|
|
|
|
if (symbolp(arg) && builtinp(arg->name)) {
|
|
|
|
uint8_t minmax = getminmax(builtin(arg->name));
|
|
|
|
if (minmax == 0327 || minmax == 0313) special = 2; // defun, setq, setf, defvar
|
|
|
|
else if (minmax == 0317 || minmax == 0017 || minmax == 0117 || minmax == 0123) special = 1;
|
|
|
|
}
|
|
|
|
while (form != NULL) {
|
|
|
|
if (atom(form)) { pfstring(PSTR(" . "), pfun); printobject(form, pfun); pfun(')'); return; }
|
|
|
|
else if (separate) {
|
|
|
|
pfun('(');
|
|
|
|
separate = false;
|
|
|
|
} else if (special) {
|
|
|
|
pfun(' ');
|
|
|
|
special--;
|
|
|
|
} else if (fits) {
|
|
|
|
pfun(' ');
|
|
|
|
} else { pln(pfun); indent(lm, ' ', pfun); }
|
|
|
|
hyperprint(car(form), lm+extra, pfun);
|
|
|
|
form = cdr(form);
|
|
|
|
}
|
|
|
|
pfun(')');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-11 12:44:51 -06:00
|
|
|
object *fn_sym_def (object *args, object *env) {
|
|
|
|
(void) env;
|
|
|
|
object *obj = first(args);
|
|
|
|
pfun_t pfun = pstreamfun(cdr(args));
|
|
|
|
#if defined(gfxsupport)
|
|
|
|
if (pfun == gfxwrite) ppwidth = GFXPPWIDTH;
|
|
|
|
#endif
|
|
|
|
object *pair = findvalue(obj, env);
|
|
|
|
object *var = car(pair);
|
|
|
|
object *val = cdr(pair);
|
|
|
|
pln(pfun);
|
|
|
|
if (consp(val) && symbolp(car(val)) && builtin(car(val)->name) == LAMBDA) {
|
2024-11-22 21:04:31 -06:00
|
|
|
hyperprint(cons(bsymbol(DEFUN), cons(var, cdr(val))), 0, pfun);
|
2024-11-11 12:44:51 -06:00
|
|
|
} else {
|
2024-11-22 21:04:31 -06:00
|
|
|
hyperprint(cons(bsymbol(DEFVAR), cons(var, cons(quote(val), NULL))), 0, pfun);
|
2024-11-11 12:44:51 -06:00
|
|
|
}
|
|
|
|
pln(pfun);
|
|
|
|
ppwidth = PPWIDTH;
|
|
|
|
return bsymbol(NOTHING);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Symbol names
|
|
|
|
const char string_sym_def[] PROGMEM = "symbol-def";
|
2024-11-11 14:36:11 -06:00
|
|
|
const char stringsavescreen[] PROGMEM = "save-screen";
|
2024-11-11 12:44:51 -06:00
|
|
|
|
|
|
|
// Documentation strings
|
|
|
|
const char doc_sym_def[] PROGMEM = "(symbol-def symbol [str])\n"
|
|
|
|
"Prints the definition of a symbol (variable or function) defined in ulisp using the pretty printer."
|
|
|
|
"If str is specified it prints to the specified stream. It returns no value.";
|
2024-11-11 16:27:44 -06:00
|
|
|
//
|
2024-11-11 14:36:11 -06:00
|
|
|
const char docsavescreen[] PROGMEM = "(save-screen filename)\n"
|
|
|
|
"Saves an image of the text screen as a BMP file on the SD card.";
|
2024-11-11 12:44:51 -06:00
|
|
|
|
|
|
|
// Symbol lookup table
|
|
|
|
const tbl_entry_t lookup_table2[] PROGMEM = {
|
2024-11-11 14:36:11 -06:00
|
|
|
{ stringsavescreen, fn_savescreen, 0211, docsavescreen },
|
2024-11-11 12:44:51 -06:00
|
|
|
{ string_sym_def, fn_sym_def, 0212, doc_sym_def }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Table cross-reference functions
|
|
|
|
|
|
|
|
tbl_entry_t *tables[] = {lookup_table, lookup_table2};
|
|
|
|
const unsigned int tablesizes[] = { arraysize(lookup_table), arraysize(lookup_table2) };
|
|
|
|
|
|
|
|
const tbl_entry_t *table (int n) {
|
|
|
|
return tables[n];
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int tablesize (int n) {
|
|
|
|
return tablesizes[n];
|
2024-11-11 16:27:44 -06:00
|
|
|
}
|