Skip to content

selphy.go - Linux client for Canon Selphy CP-900 photo printer

Last month I ran into a Canon Selphy CP-900 photo printer. It's a pretty neat device, prints pictures with pretty good quality. It even worked out of the box in Linux, but only via USB, and by it pretending to be an ordinary printer. This can have pretty ugly results.

The CP-900, as the first one in the Selphy series, can also take print jobs over WiFi. The nice thing is, other than it being wireless, that the WiFi protocol is just a pretty simple JPEG file transfer mechanism. Just giving the printer a JPEG and have it figure out layout/crop/etc seems to give somewhat nicer results. But of course, only Windows/OSX/smartphone clients are available. Fortunately, after some staring at wireshark, I managed to create a new client for it.

For extra fun, it's written in Go. My first time using the language, and I quite like it. It means the tool is very easy to build, and there are no special dependencies at all, as the Go base libraries already have everything I need.

To try it:
bzr branch
And yes, I'm still using bzr. Deal with it. :-)


No Trackbacks


Display comments as Linear | Threaded

Giorgos on :

Hey! Thanks for publishing your code. I've tested this and it works :) Do you happen to have arond a workflow or pseudocode of the protocol?


Wilmer on :

There's a file in the repo with an annotated dump of the protocol, I'm afraid that's the best I have.

It mostly works, but annoyingly the printer seems to choke on subsequent jobs, you need to powercycle it before it picks up a new one. I need to find out where that's going wrong. :-(

Still, print quality this way is already so much better than when using the device as a normal printer.

Giorgos on :

Got it, thnx! I do experience the same problem with subsequent jobs. let's see if we can figure this out.

Wilmer on :

Yeah, let me know if you find out. Testing this software is a little expensive and the printer isn't actually mine, doesn't help either.

The problem is, I think, a document ID which is sent when the job is accepted, which should be echoed in messages through the rest of the connection. I thought I was doing that now, but apparently not.

Valentin on :

Hi, I can't compile your code :(

Here are the errors.

go build selphy.go
# command-line-arguments
./selphy.go:197: method c.discover_reply is not an expression, must be called
./selphy.go:221: method c.id_reply is not an expression, must be called
./selphy.go:234: method c.status_reply is not an expression, must be called
./selphy.go:255: method c.start_tcp is not an expression, must be called
./selphy.go:284: method c.print_data_request is not an expression, must be called
./selphy.go:298: method c.send_flags_cb is not an expression, must be called
./selphy.go:312: method c.send_chunk_cb is not an expression, must be called
./selphy.go:372: method c.job_done is not an expression, must be called
./selphy.go:463: method p.start_job is not an expression, must be called
make: *** [selphy] Error 2

if you can point out what I miss that would be great.

Wilmer on :

Strange. Is that a very old version of Go? I definitely haven't seen that error before..

Valentin on :

Hi thanks for pointing this out. indeed I used standard debian go package 1.0.2, The newest version compiled it with no problem.

Thanks again.

Wilmer on :

Excellent, thank you for letting me know! Strange, I thought go was supposed to be stable after the 1.0 release..

Chris on :


thanks for your code, works great for me except for the powercylce issue...
I even wrote a litte script to use it directly from KDE (through "open with").
I only wonder if it was possible to somewhat powercycle your printer from remote?

Wilmer on :

Funny thing you ask, because in fact I've discovered a way to powercycle it! I don't remember exactly what it was, but there's a /discover or so URL you can request from it. If you mistype it slightly that crashes and reboots the printer.

I'll see if I can find it back, with a bit of luck it's even somewhere in the source code already!

Peter on :

Did you find it?

Wilmer on :

No. :-( It was a /discover or so URL that I saw somewhere else with a very simple typo in it, but when I attempted to recreate it at the time I couldn't remember the exact mistake to make.

(And it took me a year to approve that comment because I'm mostly neglecting this spam-attacked blog, powered with such shitty software that even I as the only author need to do captchas and moderate my own comments using those same credentials. :< )

Chris on :

Just noticed the printer needs a powercycle even if the previous print was done by the Android app (and not through selphy.go). I therefore guess the printer expects some init command before accepting jobs (which is probably set automatically after first boot).
You should maybe have a look in your wireshark logs again.
When comparing android-selphy-app logs with selphy.go logs I just recognized that the Android app sends a "standard query response (0x0000, "QM")" first to which the printer replies with a cache flush. Selphy.go doesn't seem to send this command. I'm currently trying to understand your source though I never used go before. Maybe the powercycle issue could be overcome if selphy.go would send 0x0000 before sending data as well...

Wilmer on :

Hrm, interesting. Maybe it's that then. I thought there was another serial number field or so in the protocol that needed setting/incrementing.

Sadly I don't own the device myself so there's not much I can do to fix this. :-(

Roland on :

Nice stuff!

Managed to compile and use it on a Raspberry Pi, and on a slow device like that it's evenmore faster than the other methods that I've found for printing to the Selphy (and this one sounds much more straightforward :-) )

It does not seem to handle error conditions like paper out / ribbon depleted smoothly yet (well, they gave me some "interesting" additional errors), but it's definitely nice to see how it's basically working, and great job! and many kudos! for finding out about the protocol!

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.

BBCode format allowed
Form options