/* User Extensions */ // Utility functions uint8_t dec_to_bcd(uint8_t n) { uint8_t bcd = 0; uint8_t tens = n / 10; bcd = tens << 4; tens *= 10; bcd += (n - tens) & 0x0f; return bcd; } uint8_t bcd_to_dec(uint8_t n) { return ((n>>4) * 10) + (n&0x0f); } /* * Standard definitions * * These definitions should be the same on every platform. */ object * fn_platform(object *args, object *env) { (void) args; (void) env; #if defined(PLATFORM_PICOCALC) const char platformName[] = ":picocalc"; #elif defined(TDECK_PERI_POWERON) /* first t-deck define */ const char platformName[] = ":t-deck"; #elif defined(ARDUINO_TEENSY41) const char platformName[] = ":teensy41"; #else const char platformName[] = ":unknown"; #endif return internlong((char *)platformName); } object * fn_bcd_to_dec(object *args, object *env) { (void) env; object *arg = car(args); int n = checkinteger(arg); if ((n < 0) || (n > 153)) { error2("number not in the range [0...#x99]."); } uint8_t result = bcd_to_dec(static_cast(n)); return number(static_cast(result)); } object * fn_dec_to_bcd(object *args, object *env) { (void) env; object *arg = car(args); int n = checkinteger(arg); if ((n < 0) || (n > 99)) { error2("number not in the range [0...99]."); } uint8_t result = dec_to_bcd(static_cast(n)); return number(static_cast(result)); } object * fn_now(object *args, object *env) { (void) env; static unsigned long Offset; unsigned long now = millis()/1000; int nargs = listlength(args); // Set time if (nargs == 3) { Offset = (unsigned long)((checkinteger(first(args))*60 \ + checkinteger(second(args)))*60 \ + checkinteger(third(args)) - now); } else if (nargs > 0) { error2(PSTR("wrong number of arguments")); } // Return time unsigned long secs = Offset + now; object *seconds = number(secs%60); object *minutes = number((secs/60)%60); object *hours = number((secs/3600)%24); return cons(hours, cons(minutes, cons(seconds, NULL))); } 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(')'); } } 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) { hyperprint(cons(bsymbol(DEFUN), cons(var, cdr(val))), 0, pfun); } else { hyperprint(cons(bsymbol(DEFVAR), cons(var, cons(quote(val), NULL))), 0, pfun); } pln(pfun); ppwidth = PPWIDTH; return bsymbol(NOTHING); } object * fn_listlibrary2(object *args, object *env) { (void) args, (void) env; object *lst = nil; GlobalStringIndex = 0; object *line = read(glibrary); while (line != NULL) { builtin_t bname = builtin(first(line)->name); if (bname == DEFUN || bname == DEFVAR) { lst = cons(second(line), lst); } line = read(glibrary); } return lst; } object * fn_lambdap(object *arg, object *env) { (void) env; if (consp(arg)) { arg = car(arg); } if (builtin(arg->name) == LAMBDA) { return tee; } return nil; } // SD card standard library. #if defined(sdcardsupport) object * fn_sd_rename(object *args, object *env) { (void) env; char buffer1[BUFFERSIZE]; char buffer2[BUFFERSIZE]; object *pathFrom = car(args); if (!stringp(pathFrom)) { error2("filenames must be strings."); } object *pathTo = car(cdr(args)); if (!stringp(pathTo)) { error2("filenames must be strings."); } if (!SD.rename((const char *)MakeFilename(pathFrom, buffer1), (const char *)MakeFilename(pathTo, buffer2))) { return nil; } return tee; } object * fn_sd_remove(object *args, object *env) { (void) env; char buffer[BUFFERSIZE]; object *arg = car(args); if (!SD.remove(MakeFilename(arg, buffer))) { return nil; } return tee; } object * fn_sd_existsp(object *args, object *env) { (void) env; char buffer[BUFFERSIZE]; object *arg = car(args); if (!SD.exists(MakeFilename(arg, buffer))) { return nil; } return tee; } /* (sd-make-dir path) Create a directory on the SD card. This will also create any intermediate directories that don’t already exists; e.g. SD.mkdir("a/b/c") will create a, b, and c. */ object * fn_sd_mkdir(object *args, object *env) { (void) env; char buffer[BUFFERSIZE]; object *arg = car(args); if (SD.mkdir(MakeFilename(arg, buffer))) { return tee; } return nil; } /* (sd-remove-dir path) Remove a directory from the SD card. The directory must be empty. */ object * fn_sd_rmdir(object *args, object *env) { (void) env; char buffer[BUFFERSIZE]; object *arg = car(args); if (SD.rmdir(MakeFilename(arg, buffer))) { return tee; } return nil; } /* * (sd-list) */ object * fn_sd_list(object *args, object *env) { (void) env; char *sd_path_buf = NULL; SDBegin(); File root; object *result = cons(NULL, NULL); object *ptr = result; if (args != NULL) { object *arg1 = checkstring(first(args)); int len = stringlength(arg1) + 2; //make it longer for the initial slash and the null terminator sd_path_buf = (char*)malloc(len); if (sd_path_buf != NULL) { cstring(arg1, &sd_path_buf[1], len-1); sd_path_buf[0] = '/'; //really weird way to add a slash at the front... root = SD.open(sd_path_buf); } } else{ root = SD.open("/"); } while (true) { File entry = root.openNextFile(); if (!entry) { break; // no more files } object *filename = lispstring((char*)entry.name()); if (entry.isDirectory()) { cdr(ptr) = cons(filename, NULL); } else{ cdr(ptr) = cons(cons(filename, number(entry.size())), NULL); } ptr = cdr(ptr); entry.close(); } if (sd_path_buf != NULL) { free(sd_path_buf); } root.close(); return cdr(result); } #endif /* * SYMBOL NAMES * * Define symbol names as const char[] PROGMEM here. */ const char stringlambdap[] PROGMEM = "lambdap"; const char stringnow[] PROGMEM = "now"; const char string_sym_def[] PROGMEM = "symdef"; const char stringbcd_to_dec[] PROGMEM = "bcd-to-dec"; const char stringdec_to_bcd[] PROGMEM = "dec-to-bcd"; const char stringlist_library2[] PROGMEM = "list-library2"; const char stringplatform[] PROGMEM = "platform"; #if defined(sdcardsupport) const char stringsd_rename[] PROGMEM = "sd-rename"; const char stringsd_remove[] PROGMEM = "sd-remove"; const char stringsd_existsp[] PROGMEM = "sd-exists-p"; const char stringsd_mkdir[] PROGMEM = "sd-make-dir"; const char stringsd_rmdir[] PROGMEM = "sd-remove-dir"; const char stringsd_dir[] PROGMEM = "sd-list"; #endif /* * DOCUMENTATION STRINGS * * Define documentation strings as const char[] PROGMEM here. */ const char doclambdap[] PROGMEM = "(lambdap x)" "Returns t if the form passed in is a lambda."; const char docnow[] PROGMEM = "(now [hh mm ss])\n" "Sets the current time, or with no arguments returns the current time\n" "as a list of three integers (hh mm ss)."; const char doc_sym_def[] PROGMEM = "(symbol-def symbol [str])\n" "Prints the definition of a symbol (variable or function) defined in\n" "ulisp using the pretty printer." "If str is specified it prints to the specified stream.\n" "It returns no value."; const char doc_bcd_to_dec[] PROGMEM = "(bcd-to-dec n)\n" "Convert the BCD-encoded number n to decimal."; const char doc_dec_to_bcd[] PROGMEM = "(dec-to-bcd n)\n" "BCD encode n."; const char doc_list_library2[] PROGMEM = "(list-library2)\n" "Return a list of all symbols in the current Lisp library."; const char doc_platform[] PROGMEM = "(platform)\n" "Returns a keyword with the current platform. Supports :picocalc,\n" ":t-deck, and :teensy41. Otherwise, returns :unknown."; #if defined(sdcardsupport) const char docsd_rename[] PROGMEM = "(sd-rename from to)\n" "Renames the file named by 'from' to 'to.'"; const char docsd_remove[] PROGMEM = "(sd-remove file)\n" "Removes the named file from the filesystem. Returns t if the file\n" "was remove successfully."; const char docsd_existsp[] PROGMEM = "(sd-exists-p file)\n" "Returns t if the named file exists."; const char docsd_dir[] PROGMEM = "(sd-list [directory])\n" "Returns a list of filenames in the root or named directory."; const char docsd_mkdir[] PROGMEM = "(sd-make-dir directory)\n" "Create a directory with the specified name. Returns t if \n" "successful, otherwise nil."; const char docsd_rmdir[] PROGMEM = "(sd-remove-dir directory)\n" "Remove the named directory. Returns t if successful, otherwise nil."; #endif // Symbol lookup table const tbl_entry_t lookup_table2[] PROGMEM = { { stringlambdap, fn_lambdap, 0211, doclambdap }, { stringnow, fn_now, 0203, docnow }, { string_sym_def, fn_sym_def, 0212, doc_sym_def }, { stringbcd_to_dec, fn_bcd_to_dec, 0211, doc_bcd_to_dec }, { stringdec_to_bcd, fn_dec_to_bcd, 0211, doc_dec_to_bcd }, { stringlist_library2, fn_listlibrary2, 0200, doc_list_library2 }, { stringplatform, fn_platform, 0200, doc_platform }, #if defined(sdcardsupport) { stringsd_rename, fn_sd_rename, 0222, docsd_rename }, { stringsd_remove, fn_sd_remove, 0211, docsd_remove }, { stringsd_existsp, fn_sd_existsp, 0211, docsd_existsp }, { stringsd_dir, fn_sd_list, 0201, docsd_dir }, { stringsd_mkdir, fn_sd_mkdir, 0211, docsd_mkdir }, { stringsd_rmdir, fn_sd_rmdir, 0211, docsd_rmdir }, #endif }; // 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]; }