13
Feb 13

Well, that’s nice…

IBM Patent Award #1

 

IBM is *really* into patents and makes it quite easy to file for one. And they have a rewards system for successful filings. Quite a few people in here have literally dozens…


04
Dec 12

First Job: Small startup or large company?

Cubicle Farm

 

Another point raised recently in a discussion on the boards.ie Development forum (we’ve had a few interesting career-related threads there of late):

When a new graduate is starting out, should they seek out jobs in small startups or large companies?

The very popular answer in the blogosphere/twitosphere/hypecentral is that the smaller startup is the better choice by a country mile, that you have a greater chance of establishing your professional reputation because you’ll have more autonomy, you’ll build more of the products, you’ll work on everything so you’ll gain a wider range of experience faster, you’ll be able to move up the ranks faster, and you’ll get to try new technologies, new techniques, new tools and new shiny things far faster than in a large monolithic company.

Maybe. But I have a different opinion.

As a first job, I’d suggest taking a role in a large company in preference to taking a role in a small one (assuming, of course, that you have the choice!). Yes, in a small company you’ll get to use more tools, take on larger projects and do more design level work.
And you won’t be ready for it and you’ll make a mess of it. Yes, you will. We all did in our first job, that’s why your first job is an entry-level one. No shame in it, you’re learning and it’s expected that you’ll be sloppy in places you didn’t know you had to be neat in, and that you’ll bite off more than you can chew, and that you’ll take on tasks that more experienced people know are doomed and wouldn’t touch with a barge pole. That’s fine. But in a small company, you can wind up being given something important to do that with and the fallout is generally not more training when you inevitably screw up! :D

In larger companies, you won’t get near design work of any magnitude for a while, but you will be surrounded by experienced people and if you want to learn and grow as a professional, that’s a pretty good environment to do a first job in. Stick it out for a year or two (or even three or four), and then once you’ve knocked off the worst of the rough edges, go for a smaller company or even a startup and use the tools and do the things you couldn’t in the larger company. Not only will you appreciate it more, but you’re likely to screw up less as a result.

Also, remember this is your first job. It’s not just software you need to be learning, but how the workplace itself operates, how to work with other people in teams on large projects (you haven’t met a large project yet, not if you’re a new graduate. The largest thing you’ll have seen in college work doesn’t even begin to approach the largest thing you’ll work on in industry) and other non-technical things that we just don’t teach in college. It’s how to get on with people that you like and people who irritate you to the point where you’d rip the skin off their face with a rabid badger if it’d make them stop talking for five minutes; it’s how to deal with managers and other bosses, both the good ones and the bad ones (and how to tell the difference); it’s how to deal with clients (though you may not see any in a really large company); it’s how the company is an actual business that needs to earn money and how that affects designs and priorities; and most importantly -if you can see it – how the company hires new hands and what they look for and how they decide how much to pay them.

Oh, and if you can learn about when to stick with the job; when not to take the job; and when (and how) to quietly resign and run for the hills – that would be a good thing too, but the odds are that you’ll be a few jobs learning that (that’s just how it goes, you need data points).

You won’t learn much about those things in a four-person startup, no matter how cool the tools or tasks they have. (Well, maybe the bit about running for the hills, or the bit about bad bosses, and you definitely will learn about the dire need for having written contracts for every last little thing; but other than that…)

Mind, you’ll be learning to eat bitter, but that’s part of the first job anywhere; it’s just that a few people in our industry think they never need to learn it (and they’re the poorer for it and they’re fairly easy to spot because they create unnecessary work for those around them). In a larger company, it’s a lot easier to learn to eat bitter (for one thing, the paycheque cushions the blow; for another, there’s usually more support and better trained managers, and less panic).

It’s not very sexy, compared to the startup world’s “f*** you” attitude and generally insufferable behaviour; but if you want to be a professional instead of a “passionate rock star artiste“, it’s probably the better choice to go work for a large company and actually learn your craft – after all, the startup mythos is always saying that college courses can’t teach you to be a great developer; so if you are going to go do the apprenticeship role, you might as well do it at a place where they’ve proven they’re good at what they do… and frankly four lads in a garage somewhere working on the next twitter clone to vanish into the aether taking all their funding with it is not a better place to learn professional practice than a fortune 500 company that’s been around for decades and shows no signs of vanishing just yet!

There was… some dissent regarding this opinion :D

 


23
Nov 12

Using VimWiki as a distributed, encrypted lab notebook for programming

So what’s the most important coding tool for a software engineer in the long-term? There’s a pretty decent argument that it’s a lab notebook. I’ve kept one for years and it’s one of the more useful tools I have, but I found that my notebook, apart from not quite measuring up to how a lab notebook should be kept, wasn’t quite as useful as it could be because when you have five or six notebooks covering a bit over a decade’s worth of notes and no search function, then how do you use them daily?

I’ve been looking around for a while for a software version of a paper notebook without much success (this isn’t ludditism – we just don’t have very much that can match what paper and pen can do for this kind of task). I’ve used a simple text editor on a cron job for a few years as a way to track what I do during the day – every 30 minutes, up pops a vim window with a ready-inserted line listing the date and time, I scribble in what I’ve done since the last time the window popped up and I save and quit – it takes about 15 seconds and it gives me a file listing everything I’ve done at the end of the day/week/month/year which is handy for things like preparing reports, doing job reviews, that sort of thing. It’s simplicity itself to set up, just call a simple script using a simpler cronjob entry:

1
2
3
4
5
6
7
8
#!/bin/bash

# Cron script for 30-min activity journal
#-------------------------------------------

export DISPLAY=:0
echo -n -e "\n[" `date` "] :\n" >> ~/.journal
/usr/bin/gvim -U ~/.journal.gvimrc -geometry 100x40+512+400 + ~/.journal
1
2
# m h dom mon dow command
0,30 8-20 * * mon-fri ~/.journal.sh

Simple and effective… but not a lab notebook. It does help test a few criteria for what I need that notebook program to do to fit in with my workflow though:

  • It has to be *fast* and familiar to use. ’nuff said, really. 
  • It has to be distributed. I work on lots of machines; I need it to be available on them, or else I’d have to have it on something like a netbook that I’d carry everywhere and that’s just not practical for me (besides, what if I forgot it or it got stolen?)
  • It has to be encrypted. Everything I work on is NDA’d at one level or another; and design/debugging notes would definitely be too sensitive to leave lying around in plaintext format. With a physical notebook, I keep it locked away; but this is supposed to be better than that option…

Colleagues have used various products for this over the years – mindmapping software; emacs in one mode or another; and various other software. But none of those really appealed. Mediawiki did seem to be as good a fit as I could find, but something that depends on an entire LAMP stack to run is hardly lightweight; and while I could host it somewhere public, that’s not really very secure (I’d spend more time making sure the full LAMP stack was up to date and mediawiki too than I want to). Besides, I’d rather this be console-accessible if possible (yes, some of us are still happier that way :) ).

I’ve been using vim since around 1993 or so; at this point it’s wired into my fingers. So when I saw vimwiki, it seemed ideal. For those who’ve not encountered vimwiki before, it creates a directory, and then every file in that directory becomes part of a rudimentary text-based wiki (which it can turn into a set of HTML pages so it can handle images and so forth, but you can also navigate it from within vim). It also has a diary function which works in a sub-directory of the wiki directory.

It doesn’t have any support for encryption or distribution. But that’s quite solvable.

The encryption is easy enough – you could use the blowfish encryption in (post-v7.3) vim but that proved a bit awkward as you had to reenter the password every time you navigated down a link (and I don’t always have post-7.3 vim available). This password entering every minute or so broke up my workflow, so no thanks. My netbook and work laptops all have whole-disk-encryption, so I just left the vimwiki directory as normal on those laptops, and on the machines where I don’t have whole-disk-encryption, I use eCryptFS to create an encrypted directory and put the wiki under that. Very simple indeed, but quite effective. Now even theft of the physical hard drive isn’t a major concern.

The distribution was equally simple; you could use any DVCS, but I’m fond of mercurial, so I decided to use that. You have to tweak the vimwiki script ( .vim/ftplugin/vimwiki.vim ) to call it:

1
2
3
4
augroup vimwiki
au! BufRead /home/mdennehy/vimwiki/index.<wbr>wiki  !hg pull;hg update
au! BufWritePost /home/mdennehy/vimwiki/*  !hg add <afile>;hg commit -m " ";hg push
augroup END</wbr>

But that’s a simple tweak at best. And you want to have ssh setup with keys for the easiest workflow, but you have that already, right? :D

Then just modify the crontab script:

1
2
3
4
5
6
#!/bin/bash
# Cron script for 30-min activity journal
#-------------------------------------------

export DISPLAY=:0
/usr/bin/gvim -U ~/.journal.gvimrc -geometry 100x40+512+400 -c "call vimwiki#diary#make_note(v:count1)" + -c "r !date +'\%n= \%H\%Mh =\%n'"

And add an Awesome keybinding and menu entry:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vimwiki_cmd = "/usr/bin/gvim -U /home/mdennehy/vimwiki/.gvimrc -c 'call vimwiki#base#goto_index(v:count1)'"

...

mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },

...
{ "VimWiki",vimwiki_cmd }
}
})

...

awful.key({ modkey, }, "w", function () awful.util.spawn(vimwiki_cmd) end),

And now whenever I hit <Mod4>-w from within Awesome, it pops up a gVim window open at the root of the wiki; every 30 minutes it pops up a gVim window in today’s diary page with the time inserted automatically for a log entry; and whenever I hit save or switch buffers, it syncs the files up to a central server’s encrypted area.

Distributed, encrypted, fast and useful. I’ve been using it in the job for the last few months now and it does almost everything I need. I do still keep around the paper notebook though – no matter how good the program, we still don’t have anything that can do everything paper can do (doodle, take cornell format notes, sketch diagrams easily for later capture, that sort of thing), but vimwiki’s search function alone is making it the day-to-day workhorse and it’s making my life a lot easier. Notes on development, patent ideas, job review reports, sysadmin notes, notes on papers I’m writing, and a daily log, all in one easy-to-use package. Damn useful tool.


21
Nov 12

Baselines

So the Coding Horror thread on boards.ie’s Development forum threw up an interesting post:

Originally Posted by COYW

[..] I was told not to comment my code, as it was a “waste of time”. Apparently, that is classic Agile!

A good code doesn’t need comments; a bad code doesn’t need comments either – it needs to be fixed! 

The responses were about as you’d expect, but in the course of answering, I made the following suggestion:

you still have your code from college exercises, right? No? You don’t keep a private archive of old code you wrote? So… how do you tell if you’re improving or getting worse without a baseline?

So I figured I’d take a peek again (last time I looked must have been before Calum was born) and compare it to what I’m writing today.

The really low-level stuff came off pretty well. Some code for programming a GAL chip for 3D2 (where you build a thin client from a 68008 chip and a handful of other chips and what feels like a mile of hand-wrapped wire):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
'       GAL1 PLDASM
'
 Address Decoding
'
'
      3D3 68008 Project
'
'
      Group 5 :
'       Mark Dennehy 93369425
'
      Ellen Delaney
'
'
      This is the address decoding code for the board. It uses one
'       GAL exclusively and the smallest selectable memory block is
'
      1024 bytes. The CLK pin is attached to /AS via an inverter.
'
'
      INPUTS :
'               A10..A19
'
              BOOT
'     /AS
'
      OUTPUTS:
'               EPROM1
'
              RAMROM1
'               RAM1
'
              RAM2
'               RAM3
'
              ACIA0
'               ACIA1
'
              LCD
'               SYSTEMBYTE
'
              TIMER<reserved>
'                    
device 22v10

'
      Input pin definitions
as = 1
a19 = 2
a18 = 3
a17 = 4
a16 = 5
a15 = 6
a14 = 7
a13 = 8
a12 = 9
a11 = 10
a10 = 11
boot = 13

'       Power & ground pin definitions
gnd = 12
vcc = 24

'
      Output pin definitions
/eprom1 = 14
/ramrom1 = 15
/ram1 = 16
/ram2 = 17
/acia0 = 18
/acia1 = 19
/lcd = 20
/sysbyte = 21
/timer = 22
/ram3 = 23

macro io   a19*a18*a17*a16;
macro rom  /a19*/a18*/a17*/a16;

start

'       EPROM selection : $00000 -> $01FFF and boot
/eprom1 /= /as*/boot*&rom*/a15*/a14*/a13;


'
      RAM_ROM selection : $00000 -> $01FFF and not-boot
'                           $20000 -> $21FFF and boot
/ramrom1 /= /as*boot*&rom*/a15*/a14*/a13 + /as*/boot*/a19*/a18*a17*/a16*/a15*/a14*/a13;


'
      RAM 1 selection : $10000 -> $107FF
/ram1 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*/a11;


'       RAM 2 selection : $10800 -> $10FFF
/ram2 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*a11;

'
      RAM 3 selection : $11000 -> $12FFF
/ram3 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*a12 + /a19*/a18*/a17*a16*/a15*/a14*a13*/a12;

'       ACIA 0 selection : $F0000
/acia0 /= /as*&io*/a15*/a14*/a13*/a12*/a11*/a10;


'
      ACIA 1 selection : $F0400
/acia1 /= /as*&io*/a15*/a14*/a13*/a12*/a11*a10;


'       LCD selection : $FE000
/lcd  /= /as*&io*a15*a14*a13*/a12*/a11*/a10;


'
      SYSTEM_BYTE selection : $FF000
/sysbyte /= /as*&io*a15*a14*a13*a12*/a11*/a10;


'  TIMER selection : $F1000
/timer /= /as*&io*/a15*/a14*/a13*a12*/a11*/a10;

end

And the assembler was about readable in most cases:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
;------------------------------------------------------------
;
;  Demonstration PICRAT program.
;
;------------------------------------------------------------
;  REVISION HISTORY :
;  
;     13/10/97 First draft, preliminary modularisation
;              of code.
;
;------------------------------------------------------------

   ERRORLEVEL  0
   PROCESSOR   PIC16C74A
   LIST     b=4
   __CONFIG _BODEN_OFF & _CP_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC
   TITLE    "Demonstration PICRAT program"
   SUBTITLE "Version 1.00"

   include     <p16c74a.inc>

;------------------------------------------------------------
;  Context Saving registers

CONTEXT     UDATA 0x20

int_w    RES   1
int_status  RES   1
int_pclath  RES   1
int_fsr     RES   1

CONTEXT2 UDATA 0xa0

int_w2      RES   1     ;Dummy Register


;------------------------------------------------------------
;  Variables used in Main Loop
Main           UDATA

tmpChar        RES   1


;------------------------------------------------------------
;
;  NAME :         RESET_VECTOR
;
;  FUNCTION :     Executes reset interrupt service routine
;  
;------------------------------------------------------------

RESET_VECTOR      CODE  0000
RESET_VECTOR
               GLOBAL   RESET_VECTOR

   PAGESEL  reset_isr
   goto  reset_isr


;--------------------ROUTINE SPECIFICATION-------------------
;
;  NAME :         INTERRUPT_VECTOR
;
;  FUNCTION :     Contect saving, correct ISR selection
;  
;  NOTES :        Saves W, STATUS, PCLATH as per ex.14-1
;              in datasheet
;
;------------------------------------------------------------
;  REVISION HISTORY :
;
;------------------------------------------------------------

INTERRUPT_VECTOR  CODE  0004
INTERRUPT_VECTOR
               GLOBAL   INTERRUPT_VECTOR

               EXTERN   USART_Tx_isr
               EXTERN   USART_Rx_isr

;INTERRUPT_VECTOR
;
;  Save the W,STATUS,PCLATH and FSR registers,

   movwf int_w
   swapf STATUS,W
   clrf  STATUS
   movwf int_status
   movf  PCLATH,W
   movwf int_pclath
   movf  FSR,W
   movwf int_fsr

;  Check to see what caused the interrupt,
;     Byte received ?

      BANKSEL  PIR1
      PAGESEL  USART_Rx_isr
      btfsc PIR1,RCIF

;        Jump to USART Rx ISR

         call  USART_Rx_isr

;     Ready to transmit byte ?

      BANKSEL  PIR1
      PAGESEL  USART_Tx_isr
      btfsc PIR1,TXIF
     
;        Jump to USART Tx ISR

         call  USART_Tx_isr
         
;     Unknown interrupt ?
;        Jump to exception handler

;        PAGESEL  Exception
;        call  Exception

;  Restore registers and return from interrupt.

   clrf  STATUS
   movf  int_fsr,W
   movwf FSR
   movf  int_pclath,W
   movwf PCLATH
   swapf int_status,W
   movwf STATUS
   swapf int_w,F
   swapf int_w,W

   retfie


;--------------------ROUTINE SPECIFICATION-------------------
;
;  NAME :         Exception
;
;  FUNCTION :     Called when an unhandled interrupt
;              condition occours.
;  
;  NOTES :       
;
;------------------------------------------------------------
;  REVISION HISTORY :
;
;------------------------------------------------------------


;EXCEPTION
;  Endless loop

Exception   CODE
Exception

   goto  Exception



;--------------------ROUTINE SPECIFICATION-------------------
;
;  NAME :         reset_isr
;
;  FUNCTION :     Reset Interrupt service routine
;              Determines correct action to perform
;              on startup.
;  
;  NOTES :       
;
;------------------------------------------------------------
;  REVISION HISTORY :
;
;------------------------------------------------------------

reset_isr         CODE
reset_isr
               GLOBAL   reset_isr

               EXTERN   MemoryTest
               EXTERN   USART_init
               EXTERN   USART_puts
               EXTERN   USART_putc
               EXTERN   USART_hi_msg_tmp
               EXTERN   USART_lo_msg_tmp
               EXTERN   Startup_screen
;              EXTERN   LCD_Initialise
;              EXTERN   LCD_PutChar
               EXTERN   USART_getc

   PAGESEL  MemoryTest
   call  MemoryTest

   PAGESEL  USART_init
   call  USART_init

;  PAGESEL  LCD_Initialise
;  call  LCD_Initialise

   PAGESEL  USART_putc
   movlw A'.'
   call  USART_putc
   movlw A'.'
   call  USART_putc
   movlw A'.'
   call  USART_putc
   movlw A'\r'
   call  USART_putc
   movlw A'\n'
   call  USART_putc

;  PAGESEL  LCD_PutChar
;  movlw A'T'
;  call  LCD_PutChar
;  movlw A'e'
;  call  LCD_PutChar
;  movlw A's'
;  call  LCD_PutChar
;  movlw A't'
;  call  LCD_PutChar

;  Enable perihiperal interrupts

   BANKSEL  INTCON
   bsf      INTCON,PEIE

;  Enable all interrupts
   bsf      INTCON,GIE

;  Print out startup message
   PAGESEL  USART_puts
   movlw high  Startup_screen
   movwf USART_hi_msg_tmp
   movlw low      Startup_screen
   movwf USART_lo_msg_tmp
   call  USART_puts

   bcf      OPTION_REG,7
   BANKSEL  PORTB
   clrf  PORTB
   BANKSEL  TRISB
   movlw 0x00
   movwf TRISB

   BANKSEL  PORTD
   clrf  PORTD
   BANKSEL  TRISD
   movlw 0x7F
   movwf TRISD

   BANKSEL  PORTE
   clrf  PORTE
   BANKSEL  TRISE
   movlw 0x07
   movwf TRISE

   PAGESEL  MainLoop
   call  MainLoop

   
;--------------------ROUTINE SPECIFICATION-------------------
;
;  NAME :         MainLoop
;
;  FUNCTION :     Main Control Interpreter
;  
;  NOTES :        A Finite State Machine
;
;------------------------------------------------------------
;  REVISION HISTORY :
;           9/1/98   First Draft
;------------------------------------------------------------

MainLoop       CODE
MainLoop
               GLOBAL   MainLoop
               EXTERN   USART_getc
               EXTERN   USART_putc
               EXTERN   AnalogRoot
               ExTERN   DigitalRoot
               EXTERN   CounterRoot
               EXTERN   PWMRoot
               EXTERN   MotorControlRoot
               EXTERN   TimerRoot

   PAGESEL  USART_getc
   call  USART_getc
   BANKSEL  tmpChar
   movwf tmpChar
   PAGESEL  MainLoop
   movf  tmpChar,W
   xorlw A'.'
   btfss STATUS,Z
   goto  MainLoop
   
;------------------------------------------------------------

ServiceSelect
   PAGESEL  USART_putc
   movlw '-'
   call  USART_putc
   movlw '-'
   call  USART_putc
   movlw '\r'
   call  USART_putc
   movlw '\n'
   call  USART_putc

   PAGESEL  USART_getc
   call  USART_getc
   movwf tmpChar

   PAGESEL  AnalogRoot
   movf  tmpChar,W
   xorlw A'a'
   btfsc STATUS,Z
   goto  AnalogRoot

   PAGESEL  DigitalRoot
   movf  tmpChar,W
   xorlw A'd'
   btfsc STATUS,Z
   goto  DigitalRoot

   PAGESEL  DigitalRoot
   movf  tmpChar,W
   xorlw A'c'
   btfsc STATUS,Z
   goto  CounterRoot

   PAGESEL  PWMRoot
   movf  tmpChar,W
   xorlw A'p'
   btfsc STATUS,Z
   goto  PWMRoot

   PAGESEL  MotorControlRoot
   movf  tmpChar,W
   xorlw A'm'
   btfsc STATUS,Z
   goto  MotorControlRoot

   PAGESEL  TimerRoot
   movf  tmpChar,W
   xorlw A't'
   btfsc STATUS,Z
   goto  TimerRoot

;------------------------------------------------------------
;  Error

   PAGESEL  USART_putc
   movlw '*'
   call  USART_putc

   goto  MainLoop




   END

Okay, so that’s not quite as good as it could be, but the libraries were better. What about the Java code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/////////////////////////////////////////////////////////////////////
//
// TACAN - TeleAutonomous Control And Navigation
//
// Mark Dennehy, 93369425
// S.S. C.Eng.
// Final Year Project 1996/7
//
//////////////////////////////////////////////////////////////////////
//
// PolarHistogram.java
//    implements the polar histogram
//  -----------------
// $Date: 1997/04/03 21:49:54 $
// $Revision: 2.0 $
// $State: Stable $
//
//////////////////////////////////////////////////////////////////////

package Tacan.RLC;

import Tacan.util.LogFile;
import Tacan.util.MathUtil;
import java.util.*;
import java.io.*;
import java.awt.event.*;

/**
 * The Polar Histogram of the Certainty value grid. This is effectively a
 * polar graph of obstacle density.
 *
 *@author
 *@version
 *@see Tacan.RLC.CVGrid
 *@see java.util.Observer
 *@see java.awt.event.ActionListener
 **/

class PolarHistogram extends Observable implements Observer, ActionListener
{
   private final static double A = 22;
   private final static double B = 1;
   private final static int maxFreeSectorSize = 18;

   private int tmpPH[];
   private RLC rlc_;
   private int no_of_segments_;
   private LogFile log_;
   private LogFile data_;
   private Vector segment_terms_[];

   /**
    * The current Polar Histogram values
    **/

   protected int PH_[];
   
   /**
    * The Local Autonomy Control graph values
    **/

   protected double LAC_[];

   /**
    * The current maximum value in the Polar Histogram (for normalisation)
    **/

   protected int PH_max = 0;

   /**
    * The current maximum value in the Local Autonomy Control graph (for normalisation)
    *@see
    **/

   protected double LAC_max = 0.0;

   /**
    * The threshold value for deciding what path is free and what is not
    **/

   protected int PH_threshold = 100;

   /**
    * The maximum network lag permitted before full local autonomy is granted (in seconds)
    **/

   public final static double maxNetLag = 10;

   /**
    * Constructor
    *
    *@param rlc The Robot Local controller instance associated with this graph
    **/

   protected PolarHistogram(RLC rlc)
   {
      rlc_ = rlc;
      PH_max = 0;
      segment_terms_ = new Vector[rlc.robot_config.PH_RES];
      no_of_segments_ = rlc.robot_config.PH_RES;
      PH_ = new int[no_of_segments_];
      tmpPH = new int[no_of_segments_];
      LAC_ = new double[no_of_segments_];
      log_ = new LogFile("Polar.log");
      data_ = new LogFile("Polar.dat");

      for (int i = 0; i<rlc.robot_config.PH_RES; i++)
         segment_terms_[i] = new Vector();

      generateSegmentTerms();
   }

   public int getThreshold()
   {
      return PH_threshold;
   }
   
   public void setThreshold(int i)
   {
      PH_threshold = i;
   }

   public void actionPerformed(ActionEvent e)
   {
      if(e.getActionCommand() == "Reset")
         reset();
   }

   protected void reset()
   {
      PH_ = new int[no_of_segments_];
   }

   private void generateSegmentTerms()
   {
      double theta, r;
      int x,y;
      int seg_no;
      double res = 360/no_of_segments_;
      int max_x = (int)(rlc_.robot_config.ACTIVE_WINDOW_SIZE/2) ;
      int max_y = max_x;
      SectorCell cell;

      System.out.print("Calculating segment terms :  ");
      System.out.flush();

      for (x = -max_x ; x <= max_x ; x++)
      {
         for (y =-max_y  ; y<=max_y  ; y++)
            if ((x!=0) || (y!=0)) // Avoid (0,0)
            {
               cell = new SectorCell(0,0,0);
               theta = MathUtil.rad2deg(Math.atan2(y,x)); //No, not a typo, atan2 takes (x,y) as (y,x)
               theta = (theta < 0) ? 360 + theta : theta ;
               
               r = Math.sqrt((x*x)+(y*y));
               cell.x = x;
               cell.y = y;
               cell.term = A - B*r;
               seg_no = (int)(theta/res);
               segment_terms_[seg_no].addElement(cell);
            }
         System.out.print(".");
         System.out.flush();
      }

      for (int i = 0; i<no_of_segments_; i++)
         segment_terms_[i].trimToSize();

      System.out.println(" Done.");
      System.out.flush();
   }

   public synchronized void update(Observable o,Object arg)
   {
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
      Enumeration sector;
      int sector_sum;
      SectorCell cell = new SectorCell(0,0,0);
      int x_offset = (int)(rlc_.robot_config.RLC_LOCAL_MAP_MAX/2);
      int y_offset = (int)(rlc_.robot_config.RLC_LOCAL_MAP_MAX/2);
      int cv;

      for (int i = 0; i < no_of_segments_; i++)
         {
            sector_sum = 0;
            sector = segment_terms_[i].elements();
            while(sector.hasMoreElements())
               {
                  cell = (SectorCell)sector.nextElement();
                  cv = rlc_.cv_grid.local_map[cell.x+x_offset][cell.y+y_offset];
                  sector_sum += cv*cv*cell.term;
               }
            tmpPH[i] = sector_sum;
         }

      smooth(5);

      setChanged();
      notifyObservers();
      Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
   }

   /**
    * Averaging filter on Polar Histogram
    *    The values for the PH can vary widely, so a smoothing filter is required
    *
    *@param filterSize The number of samples to use to smooth the graph
    *@return void
    */

   protected synchronized void smooth(int filterSize)
   {
      int sum = 0;
      PH_max = 0;

      if ((filterSize%2)==0) //If even, make odd
         filterSize++;

      int df = (int)((double)filterSize/2);

      for(int i = 0; i < no_of_segments_; i++)
      {
         sum = 0;
         for (int j = -df; j <= df; j++)           sum += tmpPH[(df+i+j)%no_of_segments_];         sum = (int)((double)sum/filterSize);         PH_[(i+df)%no_of_segments_] = sum;        PH_max = (sum > PH_max) ? sum : PH_max;
      }
   }
   
   public synchronized void LACupdate(int t,int desired_sector)
   {
      double b = (t<maxNetLag) ? (double)t/maxNetLag : 1.0 ;
      LAC_max = 0;

      double slope = (1-b)/(no_of_segments_/2);

      for (int i = 0 ; i < no_of_segments_ ; i++)
         {
         LAC_[(desired_sector+i)%no_of_segments_] = b;
         LAC_[(desired_sector+i)%no_of_segments_] += (i < (int)(no_of_segments_/2)) ? (double)i*(slope) : (-slope)*(double)(i-no_of_segments_);          LAC_max = (LAC_[i] > LAC_max) ? LAC_[i] : LAC_max;
         }
   }

   public int clearPath(int bearing)
   {
      int res = (int)360.0/no_of_segments_;
      int desired_sector = (int)(bearing/res);
      int b;
      int l_centre =1;
      int l_width = 1;
      int r_centre =1;
      int r_width = 1;

      LACupdate(3,desired_sector);

      if ((PH_[desired_sector] * LAC_[desired_sector]) < PH_threshold)
         return bearing;
      else
      {
         //Scan Left
         for(int a = 1; a < (no_of_segments_/2) ; a++)
            //Start of first free sector
            if ((PH_[(a+desired_sector)%no_of_segments_] * LAC_[(a+desired_sector)%no_of_segments_]) < PH_threshold)
            {
               //For up to maximum sector width
               for (l_width = 1; l_width <= maxFreeSectorSize; l_width++)                    //Look for end of free Sector                   if ((PH_[(a+l_width+desired_sector)%no_of_segments_] * LAC_[(a+l_width+desired_sector)%no_of_segments_]) > PH_threshold)
                     {
                        //Set centre of sector
                        l_centre = a+(int)(l_width/2);
                        break;
                     }
               break;
            }

         //Scan Right
         for(int a = no_of_segments_-1; a > (no_of_segments_/2) ; a--)
            //Start of first free sector
            if ((PH_[(a+desired_sector)%no_of_segments_] * LAC_[(a+desired_sector)%no_of_segments_]) < PH_threshold)
            {
               //For up to maximum sector width
               for (r_width = 1; r_width <= maxFreeSectorSize; r_width++)                    //Look for end of free Sector                   if ((PH_[a-r_width] * LAC_[a-r_width]) > PH_threshold)
                     {
                        //Set centre of sector
                        r_centre = a-(int)(r_width/2);
                        break;
                     }
               break;
            }

         //Choose left or right, weighing size of sector with deflection
         b = ((l_width/l_centre) > (r_width/(no_of_segments_ - r_centre))) ?  l_centre : r_centre ;  
         b += desired_sector;
         b %= no_of_segments_;
         b *= res;
         
         return b;
      }
   }

   public String toString()
   {
      String s = "[ ";
      for (int i = 0;i<no_of_segments_;i++)
         s += String.valueOf(PH_[i]) + " ";
      s += "]";
      return s;
   }
}

Oh dear. That’s very much a curate’s egg. Some parts are okay, but some… well, I wouldn’t give them an okay in a code review session today. Still, I suppose that’s a good thing – remind yourself that you were just not as hot as a teenage coder as you thought you were, and that you’ve gotten better in the interim.

What about the C++ though?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/****************************************************************
 *                                                              *
 * TCD Robocup Project 1996/7                              *
 * Intelligent Agents Group                                *
 * (Artifical Intelligence Group)                          *
 *                                                              *
 ****************************************************************
 RCS Block :

   $Author: mdennehy $
   $Date: 1996/09/07 15:57:18 $
   $RCSfile: main.cc,v $
   $Revision: 1.6 $
 ****************************************************************
   $Log: main.cc,v $
// Revision 1.6  1996/09/07  15:57:18  mdennehy
// Final version by mdennehy.
// Now knows how to locate itself on the field and
// can determine the error in this measurement.
//
// Revision 1.5  1996/09/04  14:03:22  mdennehy
// Visual and Audio parsing working.
// Minor bug : if more than 5/6 agents connected, Bus errors/segmentation faufollow
//
// Revision 1.4  1996/08/30  17:31:38  mdennehy
// First Working Version
//
// Revision 1.3  1996/08/26  15:10:49  mdennehy
// *** empty log message ***
//
// Revision 1.2  1996/08/24  16:25:08  mdennehy
// Added Threads
//
// Revision 1.1  1996/08/22  14:34:30  mdennehy
// Initial revision
//
 ****************************************************************/


/***** RCS Program Information *****/
char RCS_revision[]="$Revision: 1.6 $";
char RCS_state[]="$State: Exp $";

/***** Header Files *****/

#include <thread.h>
#include <synch.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <siginfo.h>
#include <signal.h>
#include <ucontext.h>

#include <stdio.h>
#include <stdlib.h>
#include <GetOpt.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <errno.h>
#include <LEDA/string.h>

#include "udpif.h"
#include "posdata.h"
#include "communications.h"
#include "dmalloc.h"

/***** Main Comms Socket *****/
UDPSocket comm;

#ifdef DEBUG
/***** Debugging Log file streams *****/
extern ofstream commlog;
extern ofstream datalog;
extern ofstream intsyslog;
#endif

/***** Function prototypes *****/
void usage();
void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo);


/***** MAIN() *****/
int main(int argc, char **argv)
{
#ifdef DEBUG
   print_statistics();
   init_debugging_logfiles();
   system_check();
   intsyslog << "int main(int argc,char **argv)" << endl;

   struct sigaction h;     // Install Signal handlers
   h.sa_flags = SA_SIGINFO;
   h.sa_sigaction = SignalHandler;
   sigaction(SIGBUS,&h,NULL);
   sigaction(SIGSEGV,&h,NULL);
#endif

int option_char ;
char *serverhost = "localhost";
int serverport = 6000;

//Get command-line options

GetOpt opt(argc,argv,"?h:p:") ;
while (option_char = opt(), option_char != EOF)
   switch (option_char)
      {
      case 'h':

         #ifdef DEBUG
         intsyslog << "Hostname CLI option : ";
         intsyslog << opt.optarg << endl;
         #endif

         serverhost = opt.optarg;
         break;
      case 'p':

         #ifdef DEBUG
         intsyslog << "Port CLI option : ";
         intsyslog << opt.optarg << endl;
         #endif

         serverport = atoi(opt.optarg);
         break;
      case '?':

         #ifdef DEBUG
         intsyslog << "Help CLI option selected" << endl;
         #endif

         usage();
         exit(-1);
      };

//Setup socket connection to server

#ifdef DEBUG
intsyslog << "Attempting to open socket connection" << endl;
intsyslog << "Hostname : " << serverhost << endl;
intsyslog << "    Port : " << serverport << endl;
#endif

comm.init_connection(serverhost,serverport);

//Player Initialisation sequence
#ifdef DEBUG
intsyslog << "Sending Team Init" << endl;
#endif

leda_string s("(init TCD)");
leda_string side,playmode;
int unum,err;

comm << s; comm >> s;

// parse returned initialisation message from server
err = sscanf(s,"(init %[lr] %i %[^)]",side.cstring(),&unum,playmode.cstring());

#ifdef DEBUG
if (err == 3)
   {
   intsyslog << "Side : " << side << endl;
   intsyslog << "Uniform Number : " << unum << endl;
   intsyslog << "Play Mode : " << playmode << endl;
   }
else
   {
   intsyslog << "Initialisation response parse failure" << endl;
   intsyslog << "Errno : " << err << endl;
   exit (-1);
   }
#endif

//Start main threads

thread_t main_thread_id;
thread_t communications;
//thread_t planning;
//thread_t execution;

thr_create(NULL,0,(void *)Communications,NULL,NULL,&communications);
//thr_create();
//thr_create();


main_thread_id = thr_self();

#ifdef DEBUG
intsyslog << "Main thread ID : " << main_thread_id << endl;
intsyslog << "Communications thread ID : " << communications << endl;
//intsyslog << "Planner thread ID : " << planning << endl;
//intsyslog << "Executer thread ID : " << execution << endl;
#endif


wait(2);
comm.send_message("(say -A1T1.PA.0000.0000.PB.1234.4321.PO2.5678.0123)",comm.S);
wait(3);
comm.send_message("(move 12 12)",comm.S);
wait(5);
while (1)
   // Just moves the agent about a bit to demonstrate the self-location system
   // Is an infinite loop so the rest of the code isn't much use here for now
{
   comm.send_message("(turn 20)",comm.S);
   wait(2);
   comm.send_message("(dash 50)",comm.S);
   wait(3);
}
while (thr_join(communications,NULL,NULL) == 0); // Wait for other threads to finish

#ifdef DEBUG
intsyslog << "Shutting Down" << endl;
commlog.close();
datalog.close();
intsyslog.close();
#endif
}
     
void usage()
// Prints out correct command-line format via STDERR
{
#ifdef DEBUG
intsyslog << "void usage()" << endl;
#endif

cerr << "Usage:\n";
cerr << "   % agent [options] TEAMNAME\n";
cerr << "      options: \n";
cerr << "         -h HOSTNAME \n";
cerr << "         -p PORTNUMBER\n";
cerr << endl; } #ifdef DEBUG void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo) // this is UNIX-specific code to handle a signal sent to the agent to signal a system-level error, // such as a bus error or a Segmentation fault. These are the only two such signals currently specially  // processed {    dmalloc_log_heap_map();    dmalloc_log_stats();    dmalloc_log_unfreed();  perror ("Last Error ");    if (SignalInfo->si_code <= 0)
   {
      intsyslog << "User Generated Signal" << endl;
      intsyslog << "User ID : " << SignalInfo->si_uid << endl;
      intsyslog << "Process ID : " << SignalInfo->si_pid << endl;
   }

   
   switch(signal)
   {
      case SIGBUS:
      {
         intsyslog << "********** ERROR :  Bus Error **********" << endl;
         cerr << "********** ERROR :  Bus Error **********" << endl;          if (SignalInfo->si_code == SI_NOINFO)
         {
            intsyslog << "No Debugging information given by system" << endl;           exit(-1);         }        switch (SignalInfo->si_code)
         {
            case BUS_ADRALN:
            {
               intsyslog << "Errno : " << SignalInfo->si_errno << endl;
               intsyslog << "Invalid Address Alignment" << endl;
               intsyslog << "Address : " ;
               intsyslog << (unsigned long)SignalInfo->si_addr;
               intsyslog << endl;
               break;
            }

            case BUS_ADRERR:
            {
               intsyslog << "Errno : " << SignalInfo->si_errno << endl;
               intsyslog << "NonExistant physical address" << endl;
               intsyslog << "Address : ";
               intsyslog << (unsigned long)SignalInfo->si_addr;
               intsyslog << endl;
               break;
            }

            case BUS_OBJERR:
            {
               intsyslog << "Errno : " << SignalInfo->si_errno << endl;
               intsyslog << "Object Specific Hardware Error" << endl;
               intsyslog << "Address : " ;
               intsyslog << (unsigned long)SignalInfo->si_addr;
               intsyslog << endl;
               break;
            }
         }
      }
      break;

      case SIGSEGV:
      {
         intsyslog << "********** ERROR : Segmentation Fault **********" << endl;
         cerr << "********** ERROR : Segmentation Fault **********" << endl;        if (SignalInfo->si_code == SI_NOINFO)
         {
            intsyslog << "No Debugging information given by system" << endl;           exit(-1);         }        else           switch(SignalInfo->si_code)
            {
               case SEGV_MAPERR:
               {
                  intsyslog << "Errno : " << SignalInfo->si_errno << endl;
                  intsyslog << "Address not mapped to object" << endl;
                  intsyslog << "Address : ";
                  intsyslog << (unsigned long)SignalInfo->si_addr;
                  intsyslog << endl;
                  break;
               }

               case SEGV_ACCERR:
               {
                  intsyslog << "Errno : " << SignalInfo->si_errno << endl;
                  intsyslog << "Invalid Permissions for mapped object" << endl;
                  intsyslog << "Address : ";
                  intsyslog << (unsigned long)SignalInfo->si_addr;
                  intsyslog << endl;
                  break;
               }
            }
      }
      break;
   }
   exit(-1);
}
#endif

Erm. Yikes. I did get better though :D

What about you? Do you check back over long periods to see how your standard of code is actually doing, rather than through the hazy pink-spectacled fog of old memories?


06
Sep 12

WTF phone calls

*ring*

ffs can’t I get any work done… “Hello?”

-”Hello?”
“Yes, hello?”
-”Hello?”

ah wtf is this… “Hello, who is this?”
-”Ah, hello, this is K from Three, how are you?”
“I’m fine, what’s up?”
-”I’m calling from Three and I just need to confirm your security details please, what is your date of birth?”

“Excuse me?”

-”What is your date of birth?”

You’re kidding me… “K, just repeat that to me, would you please?”

-sounding fustrated now “I’m calling from Three. I just need to verify your identity. Could you confirm your security details please, what is your date of birth?”

“K, you’ve called me on my personal phone, and you want me to give you *my* security details? Does that not sound like a really dumb idea to you?”

-”It’s just to verify your identity sir”

How did I wake up in a standup routine? “Thank you K, but I’m not going to be doing that today”

-”I can’t continue with this call then sir”

oh, the loss… “Grand, bye” <click>

Seriously?
Who thinks this is a sane way to try to contact customers?


Switch to our mobile site

Stochastic Geometry is Stephen Fry proof thanks to caching by WP Super Cache

Optimized by SEO Ultimate