Before there were standards like iBeacon and Eddystone we had to “roll our own.” This is a primitive beacon using a PIC10F200 (8pin DIP) along with a simple 315MHz OOK transmitter. Later versions, not shown here, use SDR.
beacon.asm
This is written in PIC assembly. It simply transmits my FCC Call sign with a number tacked on the end. Production versions would substitute a UUID and checksum in place of my Call sign. The signal is intentionally weak, we only want to know if the watch (wearable device) is within a few meters. Battery life is important too, this thing should be good for about 57 years on a couple AAA batteries.
The gist of what this code does is to set a timer and go to sleep. When the timer expires the chip wakes up and increments some counter (the timer durations are rather short) and we need some randomization to minimize the possibility of interference betwixt proximal beacons*. If it’s time to send a burst, my Call sign, then it does so, resets the counter and timer and goes back to sleep. The idea is to spend as much time asleep as possible to conserve batteries.
beacon.asm
| 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 | ; FILE: beacon.asm ; AUTH: Tim Allen ; DATE: 1.0 - 18 April `11 ; DESC: Controls a 315MHz radio, sends a  ;	serial number periodically (~30s) ; NOTE: Tested on PIC10F200 	include <p10f200.inc> 	list	p=10F200 	radix	hex 	__config _WDT_ON ;---------------------------------------------------------------------- ;	macro(s) xmit	macro	r0 	call	txstart 	movlw	r0 	call	txhex 	call	txstop 	endm ;---------------------------------------------------------------------- ; ram "variables" cblock	0x10  warmcnt	; counter for radio warm-up  count0		; counter for main prog  txcount	; counter for tx0 and tx1  hex		; scratch for txhex  xmitcnt	; bit counter for txhex  lfsr		; pseudo-random number endc ;---------------------------------------------------------------------- 	org	0x000 	goto	main main	;code start	 	movlw	b'11001111'	; set watchdog post-scaler 	option 	movlw	b'11111000'	; 0,1,& 2 output 	tris	GPIO		; set GPIO I/O  	btfss	STATUS,NOT_PD 	goto 	run ;---------------------------------------------------------------------- powerup	; initialize things 	clrwdt			; clear watchdog timer 	movlw	b'00000000' 	movwf	GPIO		; turn GPIOs off 	movlw	0x05 	movwf	count0		; initialize the counter 	goto	burst		; send an initial burst ;---------------------------------------------------------------------- run	; is it time for a burst? 	decfsz	count0,F 	sleep			; no go back to sleep 	; generate a pseudo-random number 	bcf	STATUS,C 	rrf	lfsr,W 	btfsc	STATUS,C 	xorlw	0xb4 	movwf	lfsr 	andlw	0x03		; limit the random to 0-3 	movwf	count0		; set the counter 	incf	count0,F	; just make sure it's not 0 burst	; send a beacon string 	bsf	GPIO,2		; power-up the radio 	movlw	0xff 	movwf	warmcnt warmlp	decfsz	warmcnt,F	; give it a sec 	goto	warmlp 	xmit	'K' 	xmit	'G' 	xmit 	'4' 	xmit	'E' 	xmit	'U' 	xmit	'K' 	xmit	'0' 	xmit	'0' 	xmit	0xf5 	bcf	GPIO,2		; power-down the radio 	sleep			; go back to sleep txstart	; transmit a start 	bsf	GPIO,0		; trigger the scope 	call	tx0 	retlw	0x00 txstop	; transmit a stop 	call	tx1 	bcf	GPIO,0		; un-trigger the scope 	retlw	0x00 tx1	; transmit a 1 bit subroutine 	bcf	GPIO,1 	movlw	d'185' 	movwf	txcount tx1lp	nop 	decfsz	txcount,F 	goto	tx1lp 	retlw	0x00 tx0	; transmit a 0 bit subroutine 	bsf	GPIO,1 	movlw	d'180' 	movwf	txcount tx0lp	nop 	decfsz	txcount,F 	goto	tx0lp 	retlw	0x00 txhex	; transmit a hex 	movwf	hex 	movlw	0x08		; set the counter 	movwf	xmitcnt nxtop	rrf	hex,F 	btfsc	STATUS,C 	goto	x1 	call	tx0		; zero 	goto 	nxbtm x1	call	tx1		; one nxbtm	decfsz	xmitcnt,F 	goto	nxtop 	retlw	0x00 	end | 
Makefile
| 1 2 3 4 5 6 7 8 | beacon.hex: beacon.asm 	gpasm beacon.asm burn: 	pk2cmd -PPIC10F200 -J -R -F beacon.hex -M clean: 	rm *.hex *.lst *.cod | 
* This is a bit tough to explain so bare with me. The oscillators on these things are not precise. So imagine we were to send a burst every 30 wake-ups (e.g. no randomization). Okay so lets say you have two of these close together and we put batteries in them at the same time. Now every 30 wake-ups they both wake up and clobber each other (the wearable can’t hear either because they “talk” over each other). Now eventually, because the oscillators are imprecise, they drift apart but that may take hours; therefore, we introduce some randomization to keep them asynchronous. I’m skipping some nuance here but I hope you get the idea.