The assignment was to build a simple client-server (in C) that solved a particular task, and the short spec (4-5 sentences) was intentionally non-specific about a number of things (that we did not care too much about anyway) but quite specific about some others. The task was similar to a small component of our embedded product, so it was relevant for the role.
The candidate would then spend half an evening or a weekend or whatever time they needed, and send us their hopefully working code. It normally took about 2 hours for someone familiar with this sort of thing, maybe 4 or 5 if they had no idea. We didn't impose any deadline, but most got back to us within a few days or after the following weekend. On a couple of occasions we never heard back.
We would then verify that the requirements were met, and we would take note of some of the design decisions where there was flexibility and things didn't matter so much. If they had at least made a good attempt we then had lots to discuss at the technical interview.
We had them walk us through the code, describing the flow and their design decisions along the way, so we could tell who actually understood what they had done. This was particularly interesting for certain sections where there were 2-3 potential ways to solve a problem, we would ask what the others were and how they had chosen to solve in this particular way, e.g. what tradeoffs they had considered. We would ask how much testing they had done (most said "thorough"), and whether they felt it met all parts of the specification (it didn't always, despite the "thorough" testing).
In all, most candidates told us they thought it was a good task without being daunting or time consuming, and we felt that we got some good insight into our candidates before we made a hiring decision. No puzzles, no grammar nazi questions!