DMP Camera Module: Shooting For The Moon

So there I was; several hours into my work on the Camera module. I may have mentioned this before, but lack of documentation is a pet peeve of mine. Unfortunately, some times it can’t be avoided. Take libgphoto2. If you click that link, you’ll get taken to a doxygen website. Seems promising, right? Go ahead and poke around, things start to look less rosy as you do. Unfortunately, this seems to be the gold standard of PTP libraries for Linux, so there’s really nothing for it. Right?

Maybe Not

After hours of frustration, I decided to try something crazy. I opened up a command prompt and entered:

gphoto2 --capture-image-and-download

And you know what? My camera took a picture and downloaded it to the current directory. Maybe that’s the answer I’m looking for. DMP Photo Booth doesn’t need to do anything fancy. It just needs to take a picture.

Now, I had been planning to provide modules that call out into Lua to allow people to implement modules in Lua. However, this was always a back-burner project. The sort of thing that happens after version 1.0 is released. But with implementing a libgphoto2 Camera Module seeming like So Much Work, maybe it was time to get on it. At least, for the Camera Module.

dmp_pb_lua_camera_module

So I committed and pushed my work on the Camera Module. I made a copy of it, and removed all the logic. After that, I committed it to the repository. It was officially official.

The first order of business was creating the lua script loader. I needed an init, finalize, and is_initialized function for lua, and a capture function. Let’s take a look:

(I’ve omitted error handling from these examples. If I didn’t they’d be 3 times as long and nobody wants to read that)

gint dmp_cm_lua_initialize() { dmp_cm_state = luaL_newstate(); luaL_openlibs(dmp_cm_state); luaL_loadfile(dmp_cm_state, DMP_CM_MODULE_SCRIPT); lua_pcall(dmp_cm_state, 0, 1, 0); lua_setglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_pushcfunction(dmp_cm_state, dmp_cm_lua_console_write); lua_setfield(dmp_cm_state, -2, "console_write"); lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_getfield(dmp_cm_state, -1, "initialize"); lua_pcall(dmp_cm_state, 0, 0, 0); is_initialized = TRUE; return DMP_PB_SUCCESS; }

First up is the initialize function. First, I initialize Lua and open the standard library. The call to luaL_loadfile loads the script and pops it onto the stack as a function, which is called by the subsequent call to lua_pcall.

If you’ve been following the blog, you may have noticed that I’m a fan of namespaces. I follow the GLib namespace style and use [NAMESPACE]::[APPLICATION/MODULE]::. I’ve decided that DMP Photo Booth modules implemented in Lua should do this as well. Lua doesn’t have actual namespaces as a language feature, but like most things, they can be approximated using tables. To that end a Lua camera module script should return a table named dmp, which contains a table named cm. In a future version, these will likely be configurable. The module will return the dmp dmp, which is set as a global in the next call.

Next, we must register the console write callback. This is accomplished by getting the dmp.cm table, pushing the console write function, and setting it as a field in dmp.cm.

Next, we get dmp.cm.initialize, and call it.

gint dmp_cm_lua_capture(gchar * location) { lua_getglobal(dmp_cm_state, DMP_CM_NAMESPACE); lua_getfield(dmp_cm_state, -1, DMP_CM_MODULE); lua_getfield(dmp_cm_state, -1, "capture"); lua_pushstring(dmp_cm_state, location); lua_pcall(dmp_cm_state, 1, 0, 0); return DMP_PB_SUCCESS; }

This is the basic method to call a function. First, get the dmp table, then get its cm field. Next, get the function from dmp.cm. After the function is on the stack, we push its arguments onto the stack, and finally we call it. The functions for finalize and is_initialized look strikingly similar, so I’ll spare you.

The Script

The script is extremely simple, thanks to Lua. I can print the whole thing here without editing it, it’s so small:

local dmp = {} dmp.cm = {} function dmp.cm.capture(location) os.execute("gphoto2 --capture-image-and-download" .. "--filename=" .. location) end function dmp.cm.initialize() end function dmp.cm.finalize() end function dmp.cm.is_initialized() return true end return dmp

In the first two lines, we create our dmp.cm namespace tables. Next we define our functions: capture, initialize, finalize, and is_initialized.

Finally, we return our namespace table for use within C. Of the four functions, only capture isn’t a placeholder. In capture, we fork and execute gphoto2, signaling our camera to capture.

How’s That Working Out For Me

Unfortunately, not so great. Well, the Lua module works perfectly. It loads, all functions call without a hitch. And a Lua script is a lot easier to implement than a C module. If only gphoto2 wasn’t so incredibly brittle.

The problem with a command line utility is that you have to count on it to work. Unfortunately, so many things can go wrong with gphoto2. So many errors, so many ways to get into an inconsistent state. Plus, my favorite part about all of this, is that all of this happens by magic! You can do the same thing twice and get different results! Take that Einstein!

No, it seems that my little forray into Lua has come to an end. The Module is live. However, work must re-start on dmp_pb_camera_module. Such a shame…

Trackbacks / Pingbacks

  1. The Smallest Things… | Doing My Programming... - January 13, 2014

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: