From 82df703d1ec450661cf15ee4ca6e02d018b6f77a Mon Sep 17 00:00:00 2001 From: Jonas S Karlsson Date: Fri, 2 Oct 2015 18:51:31 +0000 Subject: [PATCH 1/5] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e9cf7c2..001eb08 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Lot's of stuff is missing... ## performace -The esp-lisp is interpreted, too keep the code small and simple. Compared to lua from the NodeMcu it's about 2x slower, but lua is compiled and uses lots of memory for functions (about 600 bytes for a simple call). +The esp-lisp is interpreted, to keep the code small and simple. Compared to lua from the NodeMcu it's about 2x slower, but lua is compiled and uses lots of memory for functions (about 600 bytes for a simple call). ## how to build From cc7721cc00f61837afb7d93e1497d515e74b11f7 Mon Sep 17 00:00:00 2001 From: Jonas S Karlsson Date: Sat, 3 Oct 2015 16:24:53 +0000 Subject: [PATCH 2/5] wifi command and wget - wifi working - wget not yet? --- esplisp.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- lisp.c | 28 ++++++++---- 2 files changed, 143 insertions(+), 11 deletions(-) diff --git a/esplisp.c b/esplisp.c index 119a63b..6aec746 100644 --- a/esplisp.c +++ b/esplisp.c @@ -3,13 +3,24 @@ /* https://www.mozilla.org/en-US/MPL/2.0/ */ /* "driver" for esp-open-rtos put in examples/lisp */ +#include + +#include "FreeRTOS.h" +#include "task.h" + #include "espressif/esp_common.h" #include "espressif/sdk_private.h" #include "FreeRTOS.h" #include "task.h" #include "queue.h" -#include +#include "ssid_config.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" #include "lisp.h" @@ -68,8 +79,117 @@ void recvTask(void *pvParameters) static xQueueHandle mainqueue; -void user_init(void) -{ +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +// can call with NULLs get the default config +void connect_wifi(char* ssid, char* password) { + ssid = ssid ? ssid : WIFI_SSID; + password = password ? password : WIFI_PASS; + + struct sdk_station_config config; + memset(config.ssid, 0, sizeof(config.ssid)); + memset(config.password, 0, sizeof(config.password)); + memcpy(config.ssid, ssid, max(strlen(ssid), sizeof(config.ssid))); + memcpy(config.password, password, sizeof(config.password)); + + sdk_wifi_set_opmode(STATION_MODE); + sdk_wifi_station_set_config(&config); +} + +// want callback for tasks +// However, how to handle multiple gets at same time? +// TODO: keep as task as maybe it's blocking? +//void http_get_task(void *pvParameters) { +int http_get(char* buff, int size, char* url, char* server) { + int successes = 0, failures = 0; + + printf("HTTP get task starting...\r\n"); + + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + struct addrinfo *res; + + printf("Running DNS lookup for %s...\r\n", url); + int err = getaddrinfo(server, "80", &hints, &res); + + if (err != 0 || res == NULL) { + printf("DNS lookup failed err=%d res=%p\r\n", err, res); + if (res) + freeaddrinfo(res); + failures++; + return 1; + } + + /* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */ + struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; + printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr)); + + int s = socket(res->ai_family, res->ai_socktype, 0); + if(s < 0) { + printf("... Failed to allocate socket.\r\n"); + freeaddrinfo(res); + vTaskDelay(1000 / portTICK_RATE_MS); + failures++; + return 2; + } + + printf("... allocated socket\r\n"); + + if(connect(s, res->ai_addr, res->ai_addrlen) != 0) { + close(s); + freeaddrinfo(res); + printf("... socket connect failed.\r\n"); + failures++; + return 3; + } + + printf("... connected\r\n"); + freeaddrinfo(res); + + // TODO: not efficient? + #define WRITE(msg) (write((s), (msg), strlen(msg)) < 0) + if (WRITE("GET ") || + WRITE(url) || + WRITE("\r\n") || + WRITE("User-Agent: esp-open-rtos/0.1 esp8266\r\n\r\n")) + #undef WRITE + { + printf("... socket send failed\r\n"); + close(s); + failures++; + return 4; + } + printf("... socket send success\r\n"); + + int r; + char* p = buff; + size--; // remove one for \0 + do { + bzero(buff, size); + r = read(s, p, size); + if (r > 0) { + p += r; + size -= r; + // printf("%s", recv_buf); + } + } while (r > 0); + + printf("... done reading from socket. Last read return=%d errno=%d\r\n", r, errno); + if (r != 0) + failures++; + else + successes++; + close(s); + return 0; +} +// vTaskDelay(1000 / portTICK_RATE_MS); + +void user_init(void) { sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); mainqueue = xQueueCreate(10, sizeof(uint32_t)); diff --git a/lisp.c b/lisp.c index 60b1483..5b98524 100644 --- a/lisp.c +++ b/lisp.c @@ -72,15 +72,11 @@ #include #include #include +#include +#include #ifndef UNIX #include "FreeRTOS.h" - #include "task.h" - - #include - //#include // enable for uart0_num_char(void) - - //#include "FreeRTOS.h" // just for MEM FREE QUESTION #define LOOP 99999 #define LOOPS "99999" @@ -88,8 +84,6 @@ #endif #ifdef UNIX - #include - #include #define LOOP 2999999 #define LOOPS "2999999" #define LOOPTAIL "(tail 2999999 0)" @@ -110,6 +104,8 @@ // TODO: move all defs into this: #include "lisp.h" +#include "compat.h" + // big value ok as it's used mostly no inside evaluation but outside at toplevel #define READLINE_MAXLEN 1024 @@ -1323,6 +1319,22 @@ void readeval(lisp* envp) { trace = 1; } else if (strcmp(ln, "trace off") == 0) { trace = 0; + } else if (strncmp(ln, "wifi", 4) == 0) { + strtok(ln, " "); // skip wifi + char* ssid = strtok(NULL, " "); + char* pass = strtok(NULL, " "); + connect_wifi(ssid, pass); + } else if (strncmp(ln, "wget", 4) == 0) { + strtok(ln, " "); // skip wget + char* server = strtok(NULL, " "); + char* url = strtok(NULL, " "); + int buffsize = 1024*16; + char* buff = calloc(buffsize, 1); + printf("SERVER=%s URL=%s\n", server, url); + int r = http_get(buff, buffsize, url, server); + printf("GET=> %d\n", r); + printf("%s<<<\n", buff); + free(buff); } else if (strlen(ln) > 0) { // lisp princ(evalGC(reads(ln), envp)); terpri(); gc(envp); From fbcf65ec3b95a7325ea074011fae1f6350ce2ddb Mon Sep 17 00:00:00 2001 From: Jonas S Karlsson Date: Sun, 4 Oct 2015 06:14:11 +0000 Subject: [PATCH 3/5] - cleanup esp driver - (env) returns current lexical env bindings - print_memory_info - much better using cmd> mem (cons 1 2) - wget works kindof portably - timing and memory summary usage for each statement prefix by "mem " to get more - counting frees/churn of objects - hide globals in trace on --- esplisp.c | 128 ++++++++++----------------------------------------- lisp.c | 135 +++++++++++++++++++++++++++++++++++++++++------------- lisp.h | 6 +-- run | 6 +-- tlisp.ccc | 45 ++++++++++++++++-- 5 files changed, 175 insertions(+), 145 deletions(-) diff --git a/esplisp.c b/esplisp.c index 6aec746..4c0000d 100644 --- a/esplisp.c +++ b/esplisp.c @@ -26,8 +26,8 @@ void lispTask(void *pvParameters) { - lisp env = lispinit(); - lisprun(&env); + lisp env = lisp_init(); + lisp_run(&env); return; // TODO: move into a mem info and profile function! @@ -38,25 +38,8 @@ void lispTask(void *pvParameters) while(1) { //vTaskDelay(300); // 3s - unsigned int mem = xPortGetFreeHeapSize(); - printf("free=%u\r\n", mem); - int start = xTaskGetTickCount(); - lisprun(&env); - int tm = (xTaskGetTickCount() - start) * portTICK_RATE_MS; - printf("free=%u USED=%u TIME=%d\r\n", xPortGetFreeHeapSize(), (unsigned int)(mem-xPortGetFreeHeapSize()), tm); - printf("======================================================================\n"); - reportAllocs(); - - start = xTaskGetTickCount(); - int i, s = 0; - for(i=0; i<1000000; i++) { s = s + 1; } - tm = (xTaskGetTickCount() - start) * portTICK_RATE_MS; - - printf("10,000,000 LOOP (100x lua) TIME=%d\r\n", tm); - printf("======================================================================\n"); - xQueueSend(*queue, &count, 0); count++; } @@ -79,6 +62,26 @@ void recvTask(void *pvParameters) static xQueueHandle mainqueue; +unsigned int lastTick = 0; +int lastMem = 0; + +void print_memory_info(int verbose) { + report_allocs(verbose); + + int tick = xTaskGetTickCount(); + int ms = (tick - lastTick) / portTICK_RATE_MS; + int mem = xPortGetFreeHeapSize(); + if (verbose) + printf("=== free=%u USED=%u bytes TIME=%d ms ===\n", mem, lastMem-mem, ms); + else { + if (mem) printf("free=%u ", mem); + if (lastMem-mem) printf("USED=%u bytes ", lastMem-mem); + if (ms) printf("TIME=%d ms ", ms); + } + lastTick = tick; + lastMem = mem; +} + #define max(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ @@ -103,93 +106,12 @@ void connect_wifi(char* ssid, char* password) { // However, how to handle multiple gets at same time? // TODO: keep as task as maybe it's blocking? //void http_get_task(void *pvParameters) { -int http_get(char* buff, int size, char* url, char* server) { - int successes = 0, failures = 0; - - printf("HTTP get task starting...\r\n"); - - const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, - }; - struct addrinfo *res; - - printf("Running DNS lookup for %s...\r\n", url); - int err = getaddrinfo(server, "80", &hints, &res); - - if (err != 0 || res == NULL) { - printf("DNS lookup failed err=%d res=%p\r\n", err, res); - if (res) - freeaddrinfo(res); - failures++; - return 1; - } - - /* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */ - struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; - printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr)); - - int s = socket(res->ai_family, res->ai_socktype, 0); - if(s < 0) { - printf("... Failed to allocate socket.\r\n"); - freeaddrinfo(res); - vTaskDelay(1000 / portTICK_RATE_MS); - failures++; - return 2; - } - - printf("... allocated socket\r\n"); - - if(connect(s, res->ai_addr, res->ai_addrlen) != 0) { - close(s); - freeaddrinfo(res); - printf("... socket connect failed.\r\n"); - failures++; - return 3; - } - - printf("... connected\r\n"); - freeaddrinfo(res); - - // TODO: not efficient? - #define WRITE(msg) (write((s), (msg), strlen(msg)) < 0) - if (WRITE("GET ") || - WRITE(url) || - WRITE("\r\n") || - WRITE("User-Agent: esp-open-rtos/0.1 esp8266\r\n\r\n")) - #undef WRITE - { - printf("... socket send failed\r\n"); - close(s); - failures++; - return 4; - } - printf("... socket send success\r\n"); - - int r; - char* p = buff; - size--; // remove one for \0 - do { - bzero(buff, size); - r = read(s, p, size); - if (r > 0) { - p += r; - size -= r; - // printf("%s", recv_buf); - } - } while (r > 0); - - printf("... done reading from socket. Last read return=%d errno=%d\r\n", r, errno); - if (r != 0) - failures++; - else - successes++; - close(s); - return 0; -} // vTaskDelay(1000 / portTICK_RATE_MS); void user_init(void) { + lastTick = xTaskGetTickCount(); + lastMem = xPortGetFreeHeapSize(); + sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); mainqueue = xQueueCreate(10, sizeof(uint32_t)); diff --git a/lisp.c b/lisp.c index 5b98524..5a7dee8 100644 --- a/lisp.c +++ b/lisp.c @@ -1,5 +1,6 @@ /* Distributed under Mozilla Public Licence 2.0 */ /* https://www.mozilla.org/en-US/MPL/2.0/ */ +/* 2015-09-22 (C) Jonas S Karlsson, jsk@yesco.org */ /* A mini "lisp machine" */ // in speed it's comparable to compiled LUA @@ -116,7 +117,7 @@ static int trace = 0; // use for list(mkint(1), symbol("foo"), mkint(3), END); lisp END = (lisp) -1; -// global symbol variables, set in lispinit() +// global symbol variables, set in lisp_init() lisp nil = NULL; lisp t = NULL; lisp LAMBDA = NULL; @@ -219,14 +220,17 @@ typedef struct func { #define MAX_TAGS 16 int tag_count[MAX_TAGS] = {0}; int tag_bytes[MAX_TAGS] = {0}; -char* tag_name[MAX_TAGS] = { "TOTAL", "string", "cons", "int", "prim", "atom", "thunk", "immediate", "func", 0 }; +int tag_freed_count[MAX_TAGS] = {0}; +int tag_freed_bytes[MAX_TAGS] = {0}; + +char* tag_name[MAX_TAGS] = { "total", "string", "cons", "int", "prim", "atom", "thunk", "immediate", "func", 0 }; int tag_size[MAX_TAGS] = { 0, sizeof(string), sizeof(conss), sizeof(intint), sizeof(prim), sizeof(thunk), sizeof(immediate), sizeof(func) }; // essentially total number of cons+atom+prim // TODO: remove ATOM since they are never GC:ed! (thunk are special too, not tracked) //#define MAX_ALLOCS 819200 // (fibo 22) //#define MAX_ALLOCS 8192 -#define MAX_ALLOCS 1024 +#define MAX_ALLOCS 1024 // keesp 15K free //#define MAX_ALLOCS 512 // keeps 17K free //#define MAX_ALLOCS 256 // keeps 21K free //#define MAX_ALLOCS 128 // keeps 21K free @@ -248,8 +252,6 @@ unsigned int used[MAX_ALLOCS/32 + 1] = { 0 }; #define ATTR(type, x, field) ((type*)x)->field #define IS(x, type) (x && TAG(x) == type ## _TAG) -void reportAllocs(); - int gettag(lisp x) { return TAG(x); return x->tag; @@ -285,14 +287,20 @@ void* salloc(int bytes) { return p; } -void sfree(void** p, int bytes) { +void sfree(void** p, int bytes, int tag) { if (bytes >= SALLOC_MAX_SIZE) { used_bytes -= bytes; return free(p); } + // store for reuse void* n = alloc_slot[bytes]; *p = n; alloc_slot[bytes] = p; + // stats + tag_freed_count[tag]++; + tag_freed_bytes[tag] += bytes; + tag_freed_count[0]++; + tag_freed_bytes[0] += bytes; } // call this malloc using ALLOC(typename) macro @@ -326,7 +334,7 @@ void* myMalloc(int bytes, int tag) { if (allocs_count >= MAX_ALLOCS) { printf("Exhaused myMalloc array!\n"); - reportAllocs(); + report_allocs(2); #ifdef UNIX exit(1); #endif @@ -356,9 +364,6 @@ lisp gc(lisp* envp) { if (envp) mark(*envp); - // if not need let's not gc - if (!needGC()) return mem_usage(0); - int count = 0; int i ; for(i = 0; i < allocs_count; i++) { @@ -377,7 +382,7 @@ lisp gc(lisp* envp) { } else { count++; if (1) { - sfree((void*)p, tag_size[TAG(p)]);; + sfree((void*)p, tag_size[TAG(p)], TAG(p));; } else { printf("FREE: %d ", i); princ(p); terpri(); // simulate free @@ -392,15 +397,61 @@ lisp gc(lisp* envp) { return mem_usage(count); } -void reportAllocs() { - terpri(); - printf("--- Allocation stats ---\n"); +void report_allocs(int verbose) { int i; + + terpri(); + if (verbose == 2) + printf("--- Allocation stats ---\n"); + + + if (verbose == 1) { + printf("\nAllocated: "); + for(i = 0; i<16; i++) + if (tag_count[i] > 0) printf("%d %s=%d bytes, ", tag_count[i], tag_name[i], tag_bytes[i]); + + printf("\n Freed: "); + for(i = 0; i<16; i++) + if (tag_freed_count[i] > 0) printf("%d %s=%d bytes, ", tag_count[i], tag_name[i], tag_bytes[i]); + + printf("\n Used: "); + } + + for(i = 0; i<16; i++) { + if (tag_count[i] > 0 || tag_freed_count[i] > 0) { + int count = tag_count[i] - tag_freed_count[i]; + int bytes = tag_bytes[i] - tag_freed_bytes[i]; + if (verbose == 2) + printf("%12s: %3d allocations of %5d bytes, and still use %3d total %5d bytes\n", + tag_name[i], tag_count[i], tag_bytes[i], count, bytes); + else if (verbose == 1 && (count > 0 || bytes > 0)) + printf("%d %s=%d bytes, ", count, tag_name[i], bytes); + } + } + + if (verbose == 2) { + for(i = 0; i<16; i++) { + if (tag_count[i] > 0 || tag_freed_count[i] > 0) { + int count = tag_count[i] - tag_freed_count[i]; + int bytes = tag_bytes[i] - tag_freed_bytes[i]; + + if (verbose == 1 && (tag_count[i] != count || tag_bytes[i] != bytes) && (tag_count[i] || tag_bytes[i])) + printf("churn %d %s=%d bytes, ", tag_count[i], tag_name[i], tag_bytes[i]); + } + } + } + for(i = 0; i<16; i++) { - if (tag_count[i] > 0) - printf("%7s: %3d allocations of %5d bytes\n", tag_name[i], tag_count[i], tag_bytes[i]); tag_count[i] = 0; tag_bytes[i] = 0; + tag_freed_count[i] = 0; + tag_freed_bytes[i] = 0; + } + + // TODO: this one doesn't make sense? + if (verbose) { + printf("\nused_count=%d ", used_count); + fflush(stdout); } } @@ -713,6 +764,11 @@ lisp divide(lisp a, lisp b) { return mkint(getint(a) / getint(b)); } lisp read_(lisp s) { return reads(getstring(s)); } lisp terpri() { printf("\n"); return nil; } +// TODO: consider http://picolisp.com/wiki/?ArticleQuote +lisp _quote(lisp* envp, lisp x) { return x; } +lisp quote(lisp x) { return list(symbol("quote"), x, END); } // TODO: optimize +lisp _env(lisp* e, lisp all) { return *e; } + // longer functions lisp eq(lisp a, lisp b) { if (a == b) return t; @@ -776,15 +832,6 @@ lisp _set(lisp* envp, lisp name, lisp v) { return v; } -lisp _quote(lisp* envp, lisp x) { - return x; -} - -// TODO: consider http://picolisp.com/wiki/?ArticleQuote -lisp quote(lisp x) { - return list(symbol("quote"), x, END); -} - ///-------------------------------------------------------------------------------- // lisp reader @@ -1084,7 +1131,7 @@ lisp evalGC(lisp e, lisp* envp) { r = eval_hlp(ATTR(thunk, r, e), &ATTR(thunk, r, env)); // immediates are immediately consumed after evaluation, so they can be free:d directly tofree->tag = 0; - sfree((void*)tofree, sizeof(thunk)); + sfree((void*)tofree, sizeof(thunk), immediate_TAG); used_count--; // TODO: move to sfree? } @@ -1160,7 +1207,7 @@ lisp funcapply(lisp f, lisp args, lisp* envp) { static lisp test(lisp*); // returns an env with functions -lisp lispinit() { +lisp lisp_init() { lisp env = nil; lisp* envp = &env; @@ -1217,6 +1264,7 @@ lisp lispinit() { PRIM(progn, -16, progn); PRIM(eval, 1, eval); PRIM(evallist, 2, evallist); + PRIM(env, -16, _env); PRIM(read, 1, read_); @@ -1238,6 +1286,11 @@ lisp lispinit() { // another small lisp in 1K lines // - https://github.com/rui314/minilisp/blob/master/minilisp.c + // neat "trick" - limit how much 'trace on' will print by injecting nil bound to nil + // in evalGC function the print ENV stops when arriving at this token, thusly + // will not show any variables defined above... + env = cons( cons(nil, nil), env ); + dogc = 1; return env; } @@ -1299,6 +1352,14 @@ void help() { terpri(); } +void run(char* s, lisp* envp) { + lisp r = reads(s); + princ(evalGC(r, envp)); terpri(); + // TODO: report parsing allocs separately? + // mark(r); + gc(envp); +} + void readeval(lisp* envp) { hello(); @@ -1326,18 +1387,26 @@ void readeval(lisp* envp) { connect_wifi(ssid, pass); } else if (strncmp(ln, "wget", 4) == 0) { strtok(ln, " "); // skip wget - char* server = strtok(NULL, " "); - char* url = strtok(NULL, " "); - int buffsize = 1024*16; + char* server = strtok(NULL, " "); if (!server) server = "yesco.org"; + char* url = strtok(NULL, " "); if (!url) url = "http://yesco.org/index.html"; + int buffsize = 128; char* buff = calloc(buffsize, 1); printf("SERVER=%s URL=%s\n", server, url); int r = http_get(buff, buffsize, url, server); printf("GET=> %d\n", r); printf("%s<<<\n", buff); free(buff); + } else if (strncmp(ln, "mem", 3) == 0) { + char* e = ln + 3; + print_memory_info(0); + if (*e) { + run(e+1, envp); + print_memory_info(2); + } } else if (strlen(ln) > 0) { // lisp - princ(evalGC(reads(ln), envp)); terpri(); - gc(envp); + print_memory_info(0); + run(ln, envp); + print_memory_info(1); } free(ln); @@ -1490,7 +1559,7 @@ static lisp test(lisp* e) { return nil; } -void lisprun(lisp* envp) { +void lisp_run(lisp* envp) { load_library(envp); readeval(envp); return; diff --git a/lisp.h b/lisp.h index a964ecd..ddffd85 100644 --- a/lisp.h +++ b/lisp.h @@ -4,9 +4,9 @@ typedef struct { short index; // index into allocs_ptr array } *lisp; -void reportAllocs(); -lisp lispinit(); -void lisprun(lisp* envp); +void report_allocs(int verbose); +lisp lisp_init(); +void lisp_run(lisp* envp); lisp princ(lisp x); lisp terpri(); diff --git a/run b/run index 7d5f126..d0d224a 100755 --- a/run +++ b/run @@ -2,9 +2,9 @@ echo "--- Lines of code ---" grep -v "^\s*//" lisp.c | grep -v "^/\*" | grep -v "^$" | wc echo -cp tlisp.ccc tlisp.c && gcc -O2 -DUNIX=1 tlisp.c lisp.c -o opt ; rm tlisp.c -cp tlisp.ccc tlisp.c && gcc -g -pg -DUNIX=1 tlisp.c lisp.c && time ./a.out ; rm tlisp.c -#cp tlisp.ccc tlisp.c && gcc --enable-checking -v -da -Q -g -O0 -DTEST=1 tlisp.c lisp.c && ./a.out ; rm tlisp.c +cp tlisp.ccc tlisp.c && gcc -O2 -DUNIX=1 tlisp.c common.c lisp.c -o opt ; rm tlisp.c +cp tlisp.ccc tlisp.c && gcc -g -pg -DUNIX=1 tlisp.c common.c lisp.c && time ./a.out ; rm tlisp.c +###cp tlisp.ccc tlisp.c && gcc --enable-checking -v -da -Q -g -O0 -DTEST=1 tlisp.c lisp.c && ./a.out ; rm tlisp.c echo echo "----------------------------------------------------------------------" echo diff --git a/tlisp.ccc b/tlisp.ccc index ea3b860..6b789a9 100644 --- a/tlisp.ccc +++ b/tlisp.ccc @@ -1,9 +1,48 @@ +/* Distributed under Mozilla Public Licence 2.0 */ +/* https://www.mozilla.org/en-US/MPL/2.0/ */ /* 2015-09-22 (C) Jonas S Karlsson, jsk@yesco.org */ -/* "test" for esp-open-rtos put in examples/lisp */ +/* "test" driver for "unix" */ +/* provides alt implementations to esplisp.c */ + +#include +#include #include "lisp.h" +#include "compat.h" + +unsigned int lastClock = 0; +int lastMem = 0; + +// TODO: use this! mcheck, mcheck_check_all, mcheck_pedantic, mprobe - heap consistency checking +// http://www.gnu.org/software/libc/manual/html_node/Heap-Consistency-Checking.html#Heap-Consistency-Checking +// http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html#Hooks-for-Malloc +// http://www.gnu.org/software/libc/manual/html_node/Obstacks.html#Obstacks +// http://stackoverflow.com/questions/10472929/gettotalmemory-allocation-in-c +// http://stackoverflow.com/questions/910172/track-c-memory-allocations +void print_memory_info(int verbose) { + report_allocs(verbose); + + int clk = clock(); + int ms = (int)((clk- lastClock) * 1000 / CLOCKS_PER_SEC); + int mem = 0; + if (verbose == 2) + printf("=== free=%u USED=%u bytes TIME=%d ms ===\n", mem, lastMem-mem, ms); + else if (verbose == 1) { + if (mem) printf("free=%u ", mem); + if (lastMem-mem) printf("USED=%u bytes ", lastMem-mem); + if (ms) printf("TIME=%d ms ", ms); + printf("\n"); + } + lastClock = clk; + lastMem = mem; +} + +void connect_wifi(char* ssid, char* password) { /* dummy */ } int main() { - lisp env = lispinit(); - lisprun(&env); + lastClock = clock(); + lastMem = 0; + + lisp env = lisp_init(); + lisp_run(&env); } From e999687a67510320bc2bf77ec192e72a4f480fc2 Mon Sep 17 00:00:00 2001 From: Jonas S Karlsson Date: Sun, 4 Oct 2015 14:45:44 +0000 Subject: [PATCH 4/5] missed one for esp --- esplisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esplisp.c b/esplisp.c index 4c0000d..8b8318b 100644 --- a/esplisp.c +++ b/esplisp.c @@ -38,7 +38,7 @@ void lispTask(void *pvParameters) while(1) { //vTaskDelay(300); // 3s - lisprun(&env); + lisp_run(&env); xQueueSend(*queue, &count, 0); count++; From 4efd483fb60ab7d0c991e8677c1a30010fe35b3f Mon Sep 17 00:00:00 2001 From: Jonas S Karlsson Date: Sun, 4 Oct 2015 15:09:21 +0000 Subject: [PATCH 5/5] update simplier build instructions for linux --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 001eb08..4d85855 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,29 @@ The esp-lisp is interpreted, to keep the code small and simple. Compared to lua ## how to build +### I want to run it on my linux/cygwin, I have GCC + +- Get https://github.com/yesco/esp-lisp +- esp-lisp> ./run + +It'll compile and run it for you, you'll have a lisp prompt. + + lisp> help + ... + +try out the commands, it also shows what functions/symbols there are + + lisp> (+ 3 4) + 7 + + lisp> (setq fac (lambda (n) (if (= n 0) 1 (* n (fac (- n 1)))))) + #func[] + + lisp> (fac 6) + 720 + +### build embeddable image and flash it to a nodemcu/EPS8266 device + In a directory: - Get https://github.com/SuperHouse/esp-open-rtos (and all it wants)