Missing Symbol during Runtime in Over-The-Air Programming Code - c
I am currently working on developing over-the-air programming support on sky motes. Attached are the files that I have so far. I am basically trying to use the sky-shell-exec example to load my modified test-deluge.ce file onto the mote. I then try to run the test-deluge file using the shell 'exec' command as done in the sky-shell-exec example.
The final goal is to load both the test-deluge.ce and hello-world.ce compiled files onto the mote and then be able to 'exec' my test-deluge.ce file which would then find the stored hello-world.ce file and do a deluge_disseminate on it.
The progression of command I am running are as follows:
1) sudo make TARGET=sky clean CLEAN=symbols.?
2) sudo make sky-shell-exec.sky TARGET=sky
3) sudo make sky-shell-exec.sky CORE=sky-shell-exec.sky TARGET=sky
4) sudo make sky-shell-exec.upload CORE=sky-shell-exec.sky
5) sudo make compile-test-deluge-executable
6) sudo make upload-test-deluge-executable
7) sudo make login
8) ls (to see that the file made it)
9) exec test-deluge.ce
At this point I get a 'Symbol not found: deluge_disseminate' error
I believe the error is in the 'CORE=...' part of the make (in step 2 above). I have inspected the symbols.c file that is filled out in step 2 of the above and indeed there is no symbol for deluge_disseminate or any of the deluge commands for that matter that I recall.
For experimentation I tried the following:
sudo make test-deluge.sky TARGET=sky
sudo make test-deluge.sky CORE=test-deluge.sky TARGET=sky
and I find that the symbols for deluge are there, but I can't proceed to properly make sky-shell-exec file since doing so erases the symbols table and writes a new one.
I feel like there must be a simple fix to this as I can run hello-world from the sky-shell-exec example directory after following the above steps (1-9).
Does anyone have an idea of how to go about this?
NOTE: There may be a bug in my test-deluge.c where I try to open 'hello-world.sky' instead of 'hello-world.ce'...I wasn't really sure which one. I haven't been able to test this yet because of the missing symbol issue explained above, but if anyone would be willing to shed light on this issue as well I would be very appreciative.
Thanks
MAKEFILE
CONTIKI = ../..
ifndef TARGET
TARGET=sky
endif
APPS = deluge serial-shell
all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0
#all: $(CONTIKI_PROJECT)
%.tgz: %.ihex
mkdir $(basename $<) ; \
mv $< $(basename $<) ; \
echo $(basename $<)/$(basename $<).ihex 600 > $(basename $<)/runfile ; \
tar czf $# $(basename $<)
%.class: %.java
javac $(basename $<).java
viewrssi: ViewRSSI.class
make login | java ViewRSSI
include $(CONTIKI)/Makefile.include
%.shell-upload: %.ce
(echo; sleep 4; echo "~K"; sleep 4; \
echo "dec64 | write $*.ce | null"; sleep 4; \
../../tools/base64-encode < $<; sleep 4; \
echo ""; echo "~K"; echo "read $*.ce | size"; sleep 4) | make login
.PHONY: compile-test-deluge-executable upload-test-deluge-executable compile-hello-world-executable upload-test-deluge-executable
compile-hello-world-executable: hello-world.ce
echo Compiled Contiki executable: $<
upload-hello-world-executable: hello-world.shell-upload
echo Uploaded Contiki executable: $<
compile-test-deluge-executable: test-deluge.ce
echo Compiled Contiki executable: $<
upload-test-deluge-executable: test-deluge.shell-upload
echo Uploaded Contiki executable: $<
sky-shell-exec.c
#include "contiki.h"
#include "shell.h"
#include "serial-shell.h"
#include "deluge.h"
#include "dev/watchdog.h"
#include "net/rime.h"
#include "dev/cc2420.h"
#include "dev/leds.h"
#include "dev/light.h"
#include "dev/sht11.h"
#include "dev/battery-sensor.h"
#include "lib/checkpoint.h"
#include "net/rime/timesynch.h"
#include <stdio.h>
#include <string.h>
int (*keep_1)(void) = deluge_disseminate;
int (*keep_2)(void) = node_id_burn;
/*---------------------------------------------------------------------------*/
PROCESS(sky_shell_process, "Sky Contiki shell");
AUTOSTART_PROCESSES(&sky_shell_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sky_shell_process, ev, data)
{
PROCESS_BEGIN();
serial_shell_init();
/*shell_blink_init();*/
shell_file_init();
shell_coffee_init();
/*shell_ps_init();*/
/*shell_reboot_init();*/
/*shell_rime_init();*/
/*shell_rime_netcmd_init();*/
/*shell_rime_ping_init();*/
/*shell_rime_debug_init();*/
/*shell_rime_sniff_init();*/
/*shell_sky_init();*/
shell_text_init();
/*shell_time_init();*/
/* shell_checkpoint_init();*/
shell_exec_init();
shell_base64_init();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
test-deluge.c
#include "contiki.h"
#include "cfs/cfs.h"
#include "deluge.h"
#include "sys/node-id.h"
#include "loader/elfloader.h"
#include <stdio.h>
#include <string.h>
#ifndef SINK_ID
#define SINK_ID 1
#endif
#ifndef FILE_SIZE
#define FILE_SIZE 1000
#endif
PROCESS(deluge_test_process, "Deluge test process");
AUTOSTART_PROCESSES(&deluge_test_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(deluge_test_process, ev, data)
{
static struct etimer et;
node_id_burn(2);
PROCESS_BEGIN();
if(node_id == SINK_ID) {
printf("Sink node: trying to transmit file.\n");
} else {
printf("Non-sink node: trying to recieve file.\n");
}
cfs_remove("hello-world.sky");
int fd = cfs_open("hello-world.sky", CFS_WRITE | CFS_READ);
if(fd < 0) {
process_exit(NULL);
}
#if 0
if(cfs_seek(fd, FILE_SIZE, CFS_SEEK_SET) != FILE_SIZE) {
printf("failed to seek to the end\n");
}
#endif
deluge_disseminate("hello-world.sky", node_id == SINK_ID);
cfs_close(fd);
etimer_set(&et, CLOCK_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
if(node_id != SINK_ID) {
fd = cfs_open("hello-world.sky", CFS_READ);
if(fd < 0) {
printf("failed to open the test file\n");
} else {
printf("Start dynamic loading\n");
int ret = elfloader_load(fd);
printf("%d\n", ret);
cfs_close(fd);
int i;
switch(ret) {
case ELFLOADER_OK:
for(i=0; elfloader_autostart_processes[i] != NULL; i++) {
printf("exec: starting process %s. \n",
elfloader_autostart_processes[i]->name);
}
autostart_start(elfloader_autostart_processes);
break;
default:
printf("Unkown return code from ELF loader (internal bug)\n");
break;
}
}
}
etimer_reset(&et);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
hello-world.c
#include "contiki.h"
#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world\n");
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
So with great help from the contiki community I was able to gather the following solution:
"Hi,
The problem is that the build system of Contiki tries to "act smart"
and excludes symbols the application apparently does not need. So in
this case the deluge_disseminate function code is optimized away from
sky-shell-exec executable. Obviously, this conflicts with the basic
intuitions that the programmer has in case of over-the-air
programming.
To work around this issue, add a reference to deluge_disseminate in
sky-shell-exec code. For example, add this line (at global scope):
int (*keep)(void) = deluge_disseminate;
You can also try to tweak GCC linker options or use a custom linker script."
Using the same trick for node_id_burn as well, test-deluge.c runs.
The corrections have been made to the above code.
Hopefully this helps anyone else out there who may be struggling with OTA code in Contiki.
Related
"unknown device-mapper task" with libdevmapper
I'm writing a simple program that is linked against libdevmapper. There's little documentation available for this library, so I'm using tools/dmsetup.c:_process_all as a reference. I'm also including the dm-ioctl.h header. Note that memory is allocated for dmt automatically. #include <libdevmapper.h> #include <sys/ioctl.h> #include "dm-ioctl.h" int main(void) { struct dm_task *dmt; if (!(dmt = dm_task_create(DM_LIST_DEVICES))) return 1; if (!dm_task_run(dmt)) return 1; return 0; } The code is simple enough, but dm_task_run fails: # gcc -Wall -o dm-test dm-test.c -ldevmapper # ./dm-test Internal error: unknown device-mapper task -1053229822 None of the ioctl calls have failed: # strace -y -e ioctl -o /dev/stdout ./dm-test 2>/dev/null ioctl(3</dev/mapper/control>, DM_VERSION, {version=4.0.0, data_size=16384, flags=DM_EXISTS_FLAG} => {version=4.43.0, data_size=16384, flags=DM_EXISTS_FLAG}) = 0 +++ exited with 1 +++
running executable files turn to be empty files when suddenly power off
I have two executable files, whose source like below: main_a.c #include "stdio.h" int main() { printf("start to copy\n"); system("cp -pRf ~/main_b main_b"); system("cp -pRf ~/main_a main_a"); printf("done\n"); } main_b.c #include "stdio.h" int main() { while (1) { printf("i'm b, i'm running\n"); } } gcc -o main_a main_a.c gcc -o main_b main_b.c then I put main_a and main_b in ~ and ~/test. I cd in ~/test, running main_b in background like this ./main_b 1>/dev/null & and run main_a in foreground link this ./main_a; sleep 100 wait a while, unplug the power, then reboot, i get two files whose size is zero and has no content in ~/test. Anybody knows why? PS: to ensure file has been replaced, i touch ~/test/main_a and ~/test/main_b two hours ago and watch, then unplug the power. touch -d "2 hours ago" ~/test/*
You should check the result code of each system(3). And I would suggest calling sync(2) at the end of function main in main_a.c
Running luajit object file from C
From the documentation: http://luajit.org/running.html luajit -b test.lua test.obj # Generate object file # Link test.obj with your application and load it with require("test") But doesn't explain how to do these things. I guess they're assuming anyone using Lua is also a C programmer, not the case with me! Can I get some help? GCC as an example. I would also like to do the same thing except from the C byte array header. I can't find documentation on this either. luajit -bt h -n test test.lua test.h This creates the header file but I don't know how to run it from C. Thanks.
main.lua print("Hello from main.lua") app.c #include <stdio.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" int main(int argc, char **argv) { int status; lua_State *L = luaL_newstate(); luaL_openlibs(L); lua_getglobal(L, "require"); lua_pushliteral(L, "main"); status = lua_pcall(L, 1, 0, 0); if (status) { fprintf(stderr, "Error: %s\n", lua_tostring(L, -1)); return 1; } return 0; } Shell commands: luajit -b main.lua main.o gcc -O2 -Wall -Wl,-E -o app app.c main.o -Ixx -Lxx -lluajit-5.1 -lm -ldl Replace -Ixx and -Lxx by the LuaJIT include and library directories. If you've installed it in /usr/local (the default), then most GCC installations will find it without these two options. The first command compiles the Lua source code to bytecode and embeds it into the object file main.o. The second command compiles and links the minimal C application code. Note that it links in the embedded bytecode, too. The -Wl,-E is mandatory (on Linux) to export all symbols from the executable. Now move the original main.lua away (to ensure it's really running the embedded bytecode and not the Lua source code file) and then run your app: mv main.lua main.lua.orig ./app # Output: Hello from main.lua
The basic usage is as follows: Generate the header file using luajit #include that header in the source file(s) that's going to be referencing its symbols Compile the source into a runnable executable or shared binary module for lua depending on your use-case. Here's a minimal example to illustrate: test.lua return { fooprint = function (s) return print("from foo: "..s) end, barprint = function (s) return print("from bar: "..s) end } test.h // luajit -b test.lua test.h #define luaJIT_BC_test_SIZE 155 static const char luaJIT_BC_test[] = { 27,76,74,1,2,44,0,1,4,0,2,0,5,52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15, 102,114,111,109,32,102,111,111,58,32,10,112,114,105,110,116,44,0,1,4,0,2,0,5, 52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15,102,114,111,109,32,98,97,114, 58,32,10,112,114,105,110,116,58,3,0,2,0,5,0,7,51,0,1,0,49,1,0,0,58,1,2,0,49,1, 3,0,58,1,4,0,48,0,0,128,72,0,2,0,13,98,97,114,112,114,105,110,116,0,13,102, 111,111,112,114,105,110,116,1,0,0,0,0 }; runtest.cpp // g++ -Wall -pedantic -g runtest.cpp -o runtest.exe -llua51 #include <stdio.h> #include <assert.h> #include "lua.hpp" #include "test.h" static const char *runtest = "test = require 'test'\n" "test.fooprint('it works!')\n" "test.barprint('it works!')\n"; int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L); lua_getglobal(L, "package"); lua_getfield(L, -1, "preload"); // package, preload, luaJIT_BC_test bool err = luaL_loadbuffer(L, luaJIT_BC_test, luaJIT_BC_test_SIZE, NULL); assert(!err); // package.preload.test = luaJIT_BC_test lua_setfield(L, -2, "test"); // check that 'test' lib is now available; run the embedded test script lua_settop(L, 0); err = luaL_dostring(L, runtest); assert(!err); lua_close(L); } This is pretty straight-forward. This example takes the byte-code and places it into the package.preload table for this program's lua environment. Other lua scripts can then use this by doing require 'test'. The embedded lua source in runtest does exactly this and outputs: from foo: it works! from bar: it works!
How to build C program that emedded Lua
I'm learning how to embed Lua into C, and start with a simple example: demo.c #include <stdio.h> #include <string.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> int main (void) { char buff[256]; int error; lua_State *L = luaL_newstate(); /* opens Lua */ luaopen_base(L); /* opens the basic library */ luaopen_table(L); /* opens the table library */ luaopen_io(L); /* opens the I/O library */ luaopen_string(L); /* opens the string lib. */ luaopen_math(L); /* opens the math lib. */ while (fgets(buff, sizeof(buff), stdin) != NULL) { error = luaL_loadbuffer(L, buff, strlen(buff), "line") || lua_pcall(L, 0, 0, 0); if (error) { fprintf(stderr, "%s", lua_tostring(L, -1)); lua_pop(L, 1); /* pop error message from the stack */ } } lua_close(L); return 0; } ====== My Local environment: evans#master:~/codebase/demo/lua$ sudo dpkg -L liblua5.2-dev /. /usr /usr/include /usr/include/lua5.2 /usr/include/lua5.2/lua.h /usr/include/lua5.2/luaconf.h /usr/include/lua5.2/lualib.h /usr/include/lua5.2/lauxlib.h /usr/include/lua5.2/lua.hpp /usr/lib /usr/lib/i386-linux-gnu /usr/lib/i386-linux-gnu/liblua5.2.a /usr/lib/i386-linux-gnu/pkgconfig /usr/lib/i386-linux-gnu/pkgconfig/lua5.2.pc /usr/share /usr/share/doc /usr/share/doc/liblua5.2-dev /usr/share/doc/liblua5.2-dev/copyright /usr/lib/i386-linux-gnu/liblua5.2.so Then: gcc -o demo demo.c -llua5.2 demo.c:3:17: fatal error: lua.h: No such file or directory compilation terminated. I also tried -llua5, -llua and all failed. ====== Finally I found a solution: gcc -o demo demo.c -I/usr/include/lua5.2 /usr/lib/i386-linux-gnu/liblua5.2.a -lm But I couldn't figure out why I cannot do that as I usual.
You will need to either specify the actual path to the header file: #include <lua5.2/lua.h> or use -I/usr/include/lua5.2, like you already figured out. When you attempt to include <lua.h>, the compiler only looks for it at /usr/include/lua.h (and a few other places that don't matter here).
Copy all your files from /usr/include/lua*.* to /usr/include/
allegro5 - How to run on Linux?
I set up Allegro 5, and could compile the following code with success: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <allegro5/allegro.h> void error(char *msg) { fprintf(stderr,"%s : %s\n", msg, strerror(errno)); exit(1); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display = NULL; if(!al_init()) error("Could not initailize allegro"); display = al_create_display(640, 480); if(!display) error("fail to display"); al_clear_to_color(al_map_rgb(0,0,0)); al_flip_display(); al_rest(10.0); al_destroy_display(display); return 0; } But after running it, it failed with the error message: Could not initailize allegro : No such file or directory. I don't know what is wrong. My OS is Ubuntu, I'd compiled the code successfully with: gcc try.c -lallegro But could not run it with: ./a.out
Allegro needs a configuration file and possibly other files to operate. From your comment, that is probably why it is not working. From the readme: " Normally the setup program and allegro.cfg will go in the same directory as the Allegro program they are controlling. This is fine for the end user, but it can be a pain for a programmer using Allegro because you may have several programs in different directories and want to use a single allegro.cfg for all of them. If this is the case you can set the environment variable ALLEGRO to the directory containing your allegro.cfg, and Allegro will look there if there is no allegro.cfg in the current directory. ... Under Unix, BeOS and MacOS X, the config file routines also check for ~/allegro.cfg, ~/.allegrorc, /etc/allegro.cfg, and /etc/allegrorc, in that order, and the keyboard and language files can be stored in your home directory or in /etc/. See more: http://alleg.sourceforge.net/stabledocs/en/readme.html#configuration