Bit Of A Hack

Home Archives
logo

Keep up to date with Bit Of A Hack...

Quick update on the fridge. [Permalink]

The fridge alarm had a melt down.

I came home one day to find that it was constantly on. It wasn't even beeping periodically, it was just a constant drone. This was a little odd because the batteries were dying. I presume it was beeping for most of the day and so the batteries got to the point where they were on the edge of being able to power the relay and so the relay current stopped the 555 from getting enough power for long enough to do the timing. Just a guess.

So anyway, it had been dodgy for a while, I had to regularly adjust it to keep the switch in line with the big ugly box that pushed it. I think it must have got stuck before I left, the Peterhouse cleaners presumably found it beeping and tried to stop it as the big ugly box was at an odd angle and so was the fridge. At this point I removed it from the fridge to make improvements.

This problem is usually solved with magnets and reed switches. Normally closed reed switches are not common but are still fairly easy to source. I got an SPDT reed switch and a "heavy duty" reed switch kit. The kit had a SPST normally open switch in it. This would obviously be useless for this application as that would cause the alarm to only sound when the fridge is shut. I replaced the switch inside the box with the separate one that I bought and had an ideal solution that required no physical contact between the two parts of the detection mechanism. Hooray!

I also added a kill switch for when things go wrong.

To summarise; the detector is now more reliable as it is a no-contact solution. There is a kill switch so the cleaners aren't driven mad if it fails (it'll ever be needed). Current is still only drawn when the fridge is open so that the batteries will last a long time.

Some pictures... (click for bigger)

Switch kit with old switch installed...

New switch housing

 

Close up of old switch, out of focus :-(

Close up of switch housing

 

The new switch, with added magic... (bent leg was removed, this was the normally open contact)

New reed switch

The emergency kill switch was stuck to the top and its purpose made clear...

Kill switch on fridge

This image shows the reed switch kit mounted to the side of the fridge (with new reed in place inside)...

Reed switch in housing

 

By .

Leave or view comments

Shut that fridge! (A quick and dirty fridge door alarm project) [Permalink]

Flats with shared kitchens. Urgh!

Flats with shared kitchens with one small fridge that is difficult to shut. URGH!

For those who don't know, I recently moved in to a flat in Cambridge for an internship during the summer. This morning when I went to get my flora out of the [very small] communal fridge, I found the fridge was slightly open and everything inside was warm. (Sigh) I had noticed that the fridge is awkward to shut, requiring more force than first anticipated. It isn't difficult to shut it but it is possible to not do it right in a hurry.

But anyway, this is the same story that you'll get from anyone who has built a fridge alarm.

So, this morning I went to maplin to get some stuff... (As always, Click image to make bigger)

Parts ready to build

What you see in the picture above is what I bought this morning when this happened. Yes, that was the cheapest way to buy 8 AA batteries, buy three times as much as you need.

These are only the pieces that the first maplin had in stock (St. Andrew's street). I had to cycle out to the 'beehive centre' to get some double sided sticky foam and a buzzer from a bigger maplin store.

It's a fairly simple build, there is an interval timer kit that uses a 555 to drive a relay. It's a little bit rubbish and I found that it doesn't have the range of times specified. It was, however, a thing that will do the job almost ready made. I connected the buzzer to the output of this timer circuit and routed the battery connections trough the microswitch. Now if the switch is not being pressed then the buzzer sounds for a short time at about once per two seconds ish. It was a very loud buzzer and so I put tape over the holes and mounted it in the box with generous amounts of double sided sticky foam to dampen the sound.

That's it really, here is the project mostly in its case... (you can see the buzzer, it has two white tabs with screw holes)

In the box

There is tape over the switch in that picture. I had to keep it quiet before it went on the fridge.

Full assembled

 This last photo shows the extra box I got that was stuck to the door of the fridge so that there was something there to press the button when the fridge was shut.

Got this all done before lunch time having started at about 9:00 AM.

So far it has worked fine apart from one slight nock of the button presser that meant it no longer reached the switch. A quick fix though. Let's hope the other users of the fridge appreciate the time and effort (and £29.11) I have put into making their food less likely to be ruined.

So here is a video...

By .

Leave or view comments

GNU Make 'percent' patterns are awkward [Permalink]

Wrote some make magic at work yesterday after much experimenting:

So, you have a tree that looks like this:

|--Makefile 
|--projects
| |--project1
| | |--project1.c
| |
| |--project2
| | |--project2.c

And you want your Makefile to generate this output after doing "make project1.o project2.o"

|--Makefile 
|--projects
| |--project1
| | |--project1.c
| |
| |--project2
| | |--project2.c
|
|--project1.o
|--project2.o
|

(If these were truly separate projects, you would probably have two makefiles. This is only an example and so the name project is probably a bad one.)

So, looks simple right? You are going to build with a gcc command like this:

gcc -c <path-to-.c> -o <path-to-.o>

And you want to build any .o file from its .c file in a folder with the same name as that c file. So you want your target to be anything matching this pattern:

%.o

(Anything that ends in ".o".) And you want the prerequisite to be the c file in the folder of the same name. With all that, you write this rule:

%.o: projects/%/%.c
    gcc -c $^ -o $@

But it won't work. Hmph! make will only expand up to one percent sign in your prerequisite pattern. ARGH! What do I do??

Well... perhaps pattern specific variables will help? These are variables that can change depending on what pattern matched the file being built.

For example, if files matching the pattern foo_%.o need to use a different compiler to files matching the pattern bar_%.o then you can do something like this;

foo_%.o: CC = gcc

bar_%.o: CC = some-other-gcc-like-thing

%.o: %.c
    $(CC) -c $^ -o $@

And this works! So perhaps you can employ a similar trick to do what you wanted before? Lets give it a go...

%.o: OBJECTNAME = %

%.o: projects/$(OBJECTNAME)/$(OBJECTNAME).c
    gcc -c $^ -o $@

Sounds like good theory. This will not work however. The pattern specific variable will not do what you want. It will be a literal percent sign as this is not expanded.

That's an easy fix though:

%.o: OBJECTNAME = $(basename $@)

$(basename VAR) removes the extension from VAR. $@ is, as usual, the target name. if your target is to be in a subdir, you may also need $(notdir VAR)

Another problem is that the variable is not set at the point where the prerequisites are expanded. I haven't looked into why this is but I presume the reason is because make follows this flow;

- invoke make with target project1.o

- parse Makefile

- found pattern specific variable definition for pattern that matches, ignore for now...

- found target pattern that matches

- expand prerequisites (pattern specific variable not yet set)

- set that pattern specific variable that was previously ignored

- build the prerequisites if needed (with variable set)

- build the file the user asked for (with variable set)

The reason this will not work is because expanding the prerequisites without the variable set results in prerequisites that do not exist, this results in "no rule to make target..." style errors.

Bummer! What now? This is where I left the office to have lunch, I returned about 45 minutes later and drowned myself in pages of the GNU make user manual. I do now know how to make this work, so here it is...

Secondary expansions. One of make's many ugly hacks. 

So, the variable isn't set the first time you expand it, the solution, expand it a second time when it is set. (Really hacky solution but it works.) You want a secondary expansion to happen after the "set pattern specific variable" happens in the flow described above.

To make the first expansion be 'ignored' by make (and leave something that can be expanded later) you use a double dollar before a variable. The first expansion simply removes the first dollar. The rule now looks like this:

%.o: projects/$$(OBJECTNAME)/$$(OBJECTNAME).c
    gcc -c $^ -o $@

To get the second expansion to happen, you simply place this line before the rule and its specific variables;

.SECONDEXPANSION:

Urgh! At least it works, putting it all together, your Makefile now looks like this;

.SECONDEXPANSION: 
%.o: OBJECTNAME = $(basename $@) 
%.o: OBJPREREQ = projects/$(OBJECTNAME)/$(OBJECTNAME).c 

%.o: $$(OBJPREREQ) 
    gcc -c $^ -o $@

Now you start to wonder, how about this makefile...

%.o: projects/$(basename $@)/$(basename $@).c 
    gcc -c $^ -o $@

It should work right? well, maybe...

The following makefile works if you try and build project1.o;

NAME = project1.o
%.o: projects/$(basename $(NAME))/$(basename $(NAME)).c 
    gcc -c $^ -o $@

You don't want this though as you want a generic rule. So you would think that if you remove the NAME variable and just use $@ instead (which should be "project1.o" at the correct point) just like in the example before this one then it should be fine. Nope! Why? That's just make I suppose. $@ simply isn't set when the prerequisites are expanded. It only expands within the build command. This feels odd, this is known at this point and is valid in a pattern specific variable. Allowing this would remove the need for the awful second expansion hack in this case.

So, the solution is this rather ugly thing:

.SECONDEXPANSION: 
%.o: OBJECTNAME = $(basename $@) 
%.o: OBJPREREQ = projects/$(OBJECTNAME)/$(OBJECTNAME).c 

%.o: $$(OBJPREREQ) 
    gcc -c $^ -o $@

(Sigh) Make!

By .

Leave or view comments

Flex is too greedy. (How to make flex lazy) [Permalink]

Flex uses regexes. A really handy feature of regexes is that you can make sub-patterns greedy or not greedy. For example, to parse a pascal style string literal you might use a regex like this:

'((.*)'')*(.*)'

This effectively says "Match a single quote, followed by any number of occurrences of {any character followed by two single quotes} followed by any number of any character, followed by another single quote". This will match the following two literals which are valid pascal string literals:

'foo bar'
'foo''bar'

The second one reduces to foo'bar in pascal.

This is not particularly useful however as it is greedy. The following pattern matches as a single string literal (while it is actually invalid pascal syntax);

'foo''bar' 'waa?'

This happens because the dot . also matches a single quote. The regex engine continues to look forward after finding the fourth single quote in the string above because this single quote could match the last dot just as well as it can match the end single quote. So the solution is to make the .* non-greedy. aka lazy. This makes the regex engine do something like "I could stop here and match the pattern so I'll not bother going any further." You do this by adding a question mark after the star and you get a regex like this:

'((.*?)'')*(.*?)'

Suddenly you have an ideal regex for your pascal style string literal. YAY! But there is a snag. Flex will not do non-greediness. :( So what's the solution now? Well, the problem was that the dot matched the single quote. if it didn't that would be fine. So how about a character class that is everything except a single quote in place of each dot?

'(([^']*)'')*([^']*)'

Suddenly the question marks are superfluous. This now matches properly. HOORAY! I really don't like this 'feature' of flex.

By .

Leave or view comments

Seeing what C is freeing [Permalink]

Say that title again but faster, faster... FASTER! Now be quiet and read;

So, I wanted to see exactly what was being freed and when in a c program. The program has many calls to the free() function and so I didn't want to have to add a printf before each one. Instead I did this...

#define DEBUG_FREE_CALLS
#ifdef DEBUG_FREE_CALLS
#define free(x) (printf("Freeing %s, (%p)\n",#x,(void*)(x)),free(x))
#endif

It barely seems worth running it through an HTML syntax highlighter because it is just a macro.

Simply place this code at the top of the source file you are debugging and now whenever there is a call to free, for example;

free(counter);

You will see a message that looks something like this:

Freeing counter, (0x8ad8188)

Neat. You can disable this behaviour temporarily by commenting out the first line.

So what's going on? Well, the magic is in the third line, it replaces any call to free with a call to printf followed by a call to free. It's fairly simple. So if you have code like;

free(abc123);

Then this macro expands it to this;

(printf("Freeing %s, (%p)\n","abc123",(void*)(abc123)),free(abc123));

You will need to include stdio.h to get the printf function but that's all. what could be simpler?
It even accounts for bizarre cases where people have done strange things like the following;

free(foo), free(bar);

This syntax is a little odd but is still valid and so who am I to judge?

Just be careful when including this code that you don't do it before including stdlib.h as this file contains the extern declaration of free;

extern void free (void *__ptr) __THROW;

This expands to the following;

extern void (printf("Freeing %s, (%p)\n","void *__ptr",(void*)(void *__ptr)),free(void *__ptr)) __THROW;

Which gives a compiler error something like this;

/usr/include/stdlib.h:488:13: error: expected declaration specifiers or ‘...’ before string constant

Which isn't a great error message.

By .

Leave or view comments

< Older Newer >

This website uses cookies. If you don't like this, please stop using this site.