Created
August 10, 2014 03:21
Human and Goon badge code for DC22
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'' ================================================================================================= | |
'' | |
'' File....... dc22_badge_human_full.spin | |
'' | |
'' Authors.... Jon "JonnyMac" McPhalen and Ryan "1o57" Clarke | |
'' Unpublished portions reverse-engineered by Aaron "P120ph37" Meriwether | |
'' MIT License | |
'' -- see below for terms of use | |
'' | |
'' E-mail..... jon@jonmcphalen.com | |
'' 1o57@10000100001.org | |
'' | |
'' ================================================================================================= | |
{{ | |
Welcome to Defcon 22. This year we would like to invite you to experiment more fully with your | |
badge -- feel free to play around with code. | |
You can load directly to RAM [F10] if you don't want to blast your firmware, but even if you do, | |
we are giving you the source from the start. The source provides a nice badge template with extra | |
objects so that you can experiment with LEDs, buttons, IR (in and out), timing, speed changes, etc. | |
Completing the challenge will at some point require you to 'update' your badge -- but for now, how | |
about changing your LED pattern? It's easier than you think! If you need help, feel free to stop | |
by the Hardware Hacking Village, or simply ask someone who has a different pattern than yours. | |
Create a new pattern -- have fun! | |
}} | |
con { timing } | |
_clkmode = xtal1 + pll16x | |
_xinfreq = 5_000_000 ' use 5MHz crystal | |
CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq ' system freq as a constant | |
MS_001 = CLK_FREQ / 1_000 ' ticks in 1ms | |
US_001 = CLK_FREQ / 1_000_000 ' ticks in 1us | |
' speed settings for power control/reduction | |
' -- use with clkset() instruction | |
XT1_P16 = %0_1_1_01_111 ' 16x crystal (5MHz) = 80MHz | |
XT1_PL8 = %0_1_1_01_110 | |
XT1_PL4 = %0_1_1_01_101 | |
XT1_PL2 = %0_1_1_01_100 | |
XT1_PL1 = %0_1_1_01_011 | |
RC_SLOW = %0_0_0_00_001 ' 20kHz | |
' program speed and terminal baud | |
B_SPEED = 20 { MHz } | |
T_BAUD = 57_600 { for terminal io } | |
IR_FREQ = 36_000 { matches receiver on DC22 badge } | |
IR_BAUD = 2400 { max supported using IR connection } | |
con { io pins } | |
RX1 = 31 ' programming / terminal | |
TX1 = 30 | |
SDA = 29 ' eeprom / i2c | |
SCL = 28 | |
PAD3 = 27 ' touch pads | |
PAD2 = 26 | |
PAD1 = 25 | |
PAD0 = 24 | |
LED7 = 23 ' leds | |
LED6 = 22 | |
LED5 = 21 | |
LED4 = 20 | |
LED3 = 19 | |
LED2 = 18 | |
LED1 = 17 | |
LED0 = 16 | |
IR_IN = 15 ' ir input | |
IR_OUT = 14 ' ir output | |
con { io configuration } | |
IS_OFF = 0 ' all bits off | |
IS_ON = -1 ' all bits on | |
IS_LOW = 0 | |
IS_HIGH = -1 | |
IS_INPUT = 0 | |
IS_OUTPUT = -1 | |
con { pst formatting } | |
#1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR | |
#14, GOTOX, GOTOY, CLS | |
con { badge types } | |
' Other values unknown so far, though UBER would be >= 6 | |
#0, HUMAN, #6, GOON | |
BADGE_TYPE = HUMAN | |
obj | |
term : "cryptofullduplexserial64" ' serial io for terminal | |
irtx : "jm_sircs_tx" ' SIRCS output | |
irrx : "jm_sircs_rx" ' SIRCS input | |
prng : "jm_prng" ' random #s | |
tmr1 : "jm_eztimer" ' asynchronous timer | |
ee : "jm_24xx512" ' eeprom access | |
pwm : "jm_pwm8" ' pwm for LEDs | |
var | |
long ms001 ' system ticks per millisecond | |
long us001 ' system ticks per microsecond | |
pub main | idx, last, button | |
setup ' setup badge io and objects | |
term.tx(CLS) ' clear the terminal | |
if(BADGE_TYPE => GOON) | |
control_humans | |
repeat until (read_pads <> %0000) ' wait for a pad press | |
idx := (prng.random >> 1) // 13 | |
repeat (idx << 1) | |
term.tx(" ") | |
idx := (prng.random >> 1) // 13 | |
term.caesar(@@Commands[idx]) | |
if(see_them) | |
quit | |
pause(250) | |
term.tx(CLS) | |
term.caesar(@Greets) | |
term.tx(CR) | |
term.otp(@Test3, @Test4) | |
term.tx(CR) | |
last := -1 ' any button to start | |
repeat | |
repeat | |
see_them | |
button := read_pads ' wait for input | |
until ((button <> %0000) and (button <> last)) ' must be new | |
last := button ' save for next check | |
case button | |
%0001: | |
start_animation(@Cylon, 0) ' start animation | |
term.caesar(@Detective) ' display crypto string | |
pause(250) ' allow clean button release | |
%0101: | |
start_animation(@Chaser, 0) | |
term.otp(@Scientist, @Driver) | |
pause(250) | |
%0111: | |
start_animation(@Police, 0) | |
term.caesar(@Diver) | |
pause(250) | |
%1000: | |
start_animation(@InOut, 0) | |
term.otp(@Politician, @Football) | |
pause(250) | |
%1001: | |
stop_animation | |
term.otp(@RayNelson, @Mystery) | |
pause(250) | |
pub see_them | ircode | |
ircode := irrx.rxcheck | |
if (ircode < 0) | |
return | |
if (ircode == $DC22) | |
start_animation(@Dalek, 3) | |
term.caesar(string(10,"DROI VSFO GO CVOOZ",CR)) | |
repeat while (anicog) | |
irrx.enable | |
if (ircode == $DC22) | |
return true | |
pub control_humans | button, sleep | |
sleep := -1 | |
repeat | |
button := read_pads | |
if(read_pads or (tmr1.seconds => sleep)) | |
irtx.tx($DC22, 16, 3) | |
term.caesar(string(12,"IQ XUHQ FTQK EXQQB",CR)) | |
start_animation(@Dalek, 3) | |
tmr1.start | |
sleep := (||prng.random) // 11 + 10 | |
pub setup | |
'' Setup badge IO and objects | |
'' -- set speed before starting other objects | |
set_speed(B_SPEED) ' set badge speed (MHz) | |
set_leds(%00000000) ' LEDs off | |
term.start(RX1, TX1, %0000, T_BAUD) ' start terminal | |
prng.seed(cnt << 2, cnt, $1057, -cnt, cnt ~> 2) ' seed prng (random #s) | |
if(BADGE_TYPE < GOON) | |
irrx.start(IR_IN) ' set up rx mode | |
irrx.enable | |
else | |
irtx.start(IR_OUT, IR_FREQ) ' set up tx mode | |
tmr1.start | |
con | |
{ ----------------------------- } | |
{ B A D G E F E A T U R E S } | |
{ ----------------------------- } | |
pub set_speed(mhz) | |
'' Sets badge clock speed | |
'' -- sets timing variables ms001 and us001 | |
'' -- note: objects may require restart after speed change | |
case mhz | |
0: clkset(RC_SLOW, 20_000) ' super low power -- sleep mode only! | |
5: clkset(XT1_PL1, 5_000_000) | |
10: clkset(XT1_PL2, 10_000_000) | |
20: clkset(XT1_PL4, 20_000_000) | |
40: clkset(XT1_PL8, 40_000_000) | |
80: clkset(XT1_P16, 80_000_000) | |
waitcnt(cnt + (clkfreq / 100)) ' wait ~10ms | |
ms001 := clkfreq / 1_000 ' set ticks per millisecond for waitcnt | |
us001 := clkfreq / 1_000_000 ' set ticks per microsecond for waitcnt | |
pub set_leds(pattern) | |
'' Sets LED pins to output and writes pattern to them | |
'' -- swaps LSB/MSB for correct binary output | |
outa[LED0..LED7] := pattern ' write pattern to LEDs | |
dira[LED0..LED7] := IS_HIGH ' make LED pins outputs | |
pub read_pads | |
'' Reads and returns state of touch pad inputs | |
'' -- swaps LSB/MSB for correct binary input | |
outa[PAD3..PAD0] := IS_HIGH ' charge pads (all output high) | |
dira[PAD3..PAD0] := IS_OUTPUT | |
dira[PAD3..PAD0] := IS_INPUT ' float pads | |
pause(50) ' -- allow touch to discharge | |
return (!ina[PAD3..PAD0] & $0F) >< 4 ' return "1" for touched pads | |
con | |
{ --------------- } | |
{ L E D F U N } | |
{ --------------- } | |
var | |
long anicog ' cog running animation | |
long anistack[32] ' stack space for Spin cog | |
pri start_animation(p_table, cycles) | |
'' Start animation in background cog | |
'' -- allows LED animation while doing other processes | |
'' -- p_table is pointer (address of) animation table | |
'' -- set cycles to 0 to run without stopping | |
stop_animation | |
anicog := cognew(run_animation(p_table, cycles), @anistack) + 1 | |
return anicog ' return cog used | |
pri stop_animation | |
'' Stop animation if currently running | |
if (anicog) ' if running | |
cogstop(anicog - 1) ' stop the cog | |
anicog := 0 ' mark stopped | |
pri run_animation(p_table, cycles) | p_leds | |
'' Run animation | |
'' -- p_table is pointer (address of) animation table | |
'' -- cycles is number of iterations to run | |
'' * 0 cycles runs "forever" | |
'' -- usually called with start_animation() | |
if (cycles =< 0) | |
cycles := POSX ' run "forever" | |
repeat cycles | |
p_leds := p_table ' point to table | |
repeat byte[p_leds++] ' repeat for steps in table | |
set_leds(byte[p_leds++]) ' update leds | |
pause(byte[p_leds++]) ' hold | |
anicog := 0 ' mark stopped | |
cogstop(cogid) ' stop this cog | |
dat | |
' Animation tables for LEDs | |
' -- 1st byte is number of steps in animation sequence | |
' -- each step holds pattern and hold time (ms) | |
' -- for delays > 255, duplicate pattern + delay | |
Cylon byte (@Cylon_X - @Cylon) / 2 + 1 | |
byte %10000000, 125 | |
byte %01000000, 125 | |
byte %00100000, 125 | |
byte %00010000, 125 | |
byte %00001000, 125 | |
byte %00000100, 125 | |
byte %00000010, 125 | |
byte %00000001, 125 | |
byte %00000010, 125 | |
byte %00000100, 125 | |
byte %00001000, 125 | |
byte %00010000, 125 | |
byte %00100000, 125 | |
Cylon_X byte %01000000, 125 | |
Chaser byte (@Chaser_X - @Chaser) / 2 + 1 | |
byte %10010010, 75 | |
byte %00100100, 75 | |
Chaser_X byte %01001001, 75 | |
InOut byte (@InOut_X - @InOut) / 2 + 1 | |
byte %10000001, 100 | |
byte %01000010, 100 | |
byte %00100100, 100 | |
byte %00011000, 100 | |
byte %00100100, 100 | |
InOut_X byte %01000010, 100 | |
Police byte (@Police_X - @Police) / 2 + 1 | |
byte %11001100, 75 | |
byte %11110000, 75 | |
byte %11001100, 75 | |
byte %11110000, 75 | |
byte %00001111, 75 | |
byte %00110011, 75 | |
byte %00001111, 75 | |
Police_X byte %00110011, 75 | |
Dalek byte (@Dalek_X - @Dalek) / 2 + 1 | |
byte %00000000, 50 | |
byte %00011000, 50 | |
byte %00111100, 50 | |
byte %01111110, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %00011000, 50 | |
byte %00111100, 50 | |
byte %01111110, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %00011000, 50 | |
byte %00111100, 50 | |
byte %01111110, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %11111111, 50 | |
byte %00000000, 50 | |
byte %11111111, 50 | |
Dalek_X byte %00000000, 50 | |
con | |
{ ------------- } | |
{ B A S I C S } | |
{ ------------- } | |
pub pause(ms) | t | |
'' Delay program in milliseconds | |
'' -- ensure set_speed() used before calling | |
t := cnt ' sync to system counter | |
repeat (ms #>= 0) ' delay > 0 | |
waitcnt(t += ms001) ' hold 1ms | |
pub high(pin) | |
'' Makes pin output and high | |
outa[pin] := IS_HIGH | |
dira[pin] := IS_OUTPUT | |
pub low(pin) | |
'' Makes pin output and low | |
outa[pin] := IS_LOW | |
dira[pin] := IS_OUTPUT | |
pub toggle(pin) | |
'' Toggles pin state | |
!outa[pin] | |
dira[pin] := IS_OUTPUT | |
pub input(pin) | |
'' Makes pin input and returns current state | |
dira[pin] := IS_INPUT | |
return ina[pin] | |
pub pulse_out(pin, us) | state | |
'' Generate pulse on pin for us microseconds | |
'' -- ensure set_speed() used before calling | |
'' -- makes pin output | |
'' -- pulse out is opposite of pin's input state | |
'' -- blocks until pulse is finished (to clear counter) | |
us *= us001 ' convert us to system ticks | |
state := ina[pin] ' read incoming state of pin | |
if (ctra == 0) ' ctra available? | |
if (state == 0) ' low-high-low | |
low(pin) ' set to output | |
frqa := 1 | |
phsa := -us ' set timing | |
ctra := (%00100 << 26) | pin ' start the pulse | |
repeat | |
until (phsa => 0) ' let pulse finish | |
else ' high-low-high | |
high(pin) | |
frqa := -1 | |
phsa := us | |
ctra := (%00100 << 26) | pin | |
repeat | |
until (phsa < 0) | |
ctra := IS_OFF ' release counter | |
return true | |
elseif (ctrb == 0) | |
if (state == 0) | |
low(pin) | |
frqb := 1 | |
phsb := -us | |
ctrb := (%00100 << 26) | pin | |
repeat | |
until (phsb => 0) | |
else | |
high(pin) | |
frqb := -1 | |
phsb := us | |
ctrb := (%00100 << 26) | pin | |
repeat | |
until (phsb < 0) | |
ctrb := IS_OFF | |
return true | |
else | |
return false ' alert user of error | |
pub set_freq(ctrx, px, fx) | |
'' Sets ctrx to frequency fx on pin px (NCO/SE mode) | |
'' -- fx in hz | |
'' -- use fx of 0 to stop counter that is running | |
if (fx > 0) | |
fx := ($8000_0000 / (clkfreq / fx)) << 1 ' convert freq for NCO mode | |
case ctrx | |
"a", "A": | |
ctra := ((%00100) << 26) | px ' configure ctra for NCO on pin | |
frqa := fx ' set frequency | |
dira[px] := IS_OUTPUT | |
"b", "B": | |
ctrb := ((%00100) << 26) | px | |
frqb := fx | |
dira[px] := IS_OUTPUT | |
else | |
case ctrx | |
"a", "A": | |
ctra := IS_OFF ' disable counter | |
outa[px] := IS_OFF ' clear pin/driver | |
dira[px] := IS_INPUT | |
"b", "B": | |
ctrb := IS_OFF | |
outa[px] := IS_OFF | |
dira[px] := IS_INPUT | |
dat | |
RayNelson byte "IAIHG TPJNU QU CZR GALWXK DC MHR LANK FOTLA OTN LOYOC HPMPB PX HKICW",0 | |
Test4 byte "DID YOU REALLY THINK THAT IT WOULD BE SO EASY? Really? Just running strings?",0 | |
Greets byte 16,77,85,66,83,69,67,85,32,74,69,32,84,85,86,83,69,68,32,74,77,85,68,74,79,32,74,77,69,13,0 | |
Detective byte 13,74,85,82,69,82,32,71,66,32,79,82,84,86,65,32,86,32,88,65,66,74,32,83,86,65,81,32,85,78,69,66,89,81,13,0 | |
Scientist byte 76,81,84,89,86,70,32,82,75,66,32,83,78,90,32,83,81,87,83,85,32,87,82,65,32,73,77,82,66,32,67,70,72,82,32,90,65,65,65,65,32,73,89,77,87,90,32,80,32,69,65,74,81,86,68,32,89,79,84,80,32,76,71,65,87,32,89,75,90,76,13,0 | |
Diver byte 10,"DBI DRO PSBCD RKVP YP RSC ZRYXO XEWLOB PYVVYGON LI RSC VKCD XKWO DROX DRO COMYXN RKVP YP RSC XEWLOB",CR,0 | |
Driver byte "SOMETIMES WE HAVE ANSWERS AND DONT EVEN KNOW IT SO ENJOY THE VIEW JUST BE HAPPY",0 | |
Politician byte 83,83,80,87,76,77,32,84,72,67,65,80,32,81,80,32,74,84,32,73,87,69,32,87,68,88,70,90,32,89,85,90,88,32,85,77,86,72,88,72,32,90,65,32,67,66,32,80,65,69,32,88,82,79,76,32,70,65,89,32,73,80,89,75,13,0 | |
Test3 byte "ZGJG MTM LLPN C NTER MPMH TW",CR,0 | |
Football byte "IT MIGHT BE HELPFUL LATER IF YOU KNOW HOW TO GET TO EDEN OR AT LEAST THE WAY",0 | |
Mystery byte "OH A MYSTERY STRING I SHOULD HANG ON TO THIS FOR LATER I WONDER WHAT ITS FOR OR WHAT IT DECODES TO?",0 | |
dat | |
Cmd00 byte $05, $42, $54, $57, $50, $20, $4A, $4E, $4C, $4D, $59, $20, $4D, $54 | |
byte $5A, $57, $58, $0D, $00, $4C, $4F, $56, $45, $00 | |
Cmd01 byte $04, $41, $45, $58, $47, $4C, $20, $58, $5A, $0D, $00 | |
Cmd02 byte $0E, $47, $49, $50, $41, $57, $48, $0D, $00, $4C, $49, $46, $45, $00 | |
Cmd03 byte $0C, $45, $46, $4D, $4B, $20, $4D, $45, $58, $51, $51, $42, $0D, $00 | |
Cmd04 byte $04, $53, $46, $49, $43, $0D, $00, $47, $69, $47, $21, $00 | |
Cmd05 byte $14, $48, $49, $20, $43, $48, $58, $59, $4A, $59, $48, $58, $59, $48 | |
byte $4E, $20, $4E, $42, $49, $4F, $41, $42, $4E, $0D, $00 | |
Cmd06 byte $02, $50, $51, $20, $4B, $4F, $43, $49, $4B, $50, $43, $56, $4B, $51 | |
byte $50, $0D, $00, $4A, $6F, $6E, $6E, $79, $4D, $61, $63, $00 | |
Cmd07 byte $0C, $59, $4D, $44, $44, $4B, $20, $4D, $5A, $50, $20, $44, $51, $42 | |
byte $44, $41, $50, $47, $4F, $51, $0D, $00, $48, $41, $50, $50, $59, $00 | |
Cmd08 byte $05, $4A, $46, $59, $0D, $00, $48, $45, $41, $4C, $54, $48, $00 | |
Cmd09 byte $09, $4D, $58, $20, $57, $58, $43, $20, $5A, $44, $4E, $42, $43, $52 | |
byte $58, $57, $20, $4A, $44, $43, $51, $58, $41, $52, $43, $48, $0D, $00 | |
Cmd10 byte $0F, $52, $44, $43, $48, $4A, $42, $54, $0D, $00 | |
Cmd11 byte $02, $45, $51, $50, $48, $51, $54, $4F, $0D, $00 | |
Cmd12 byte $19, $41, $54, $58, $0D, $00, $57, $45, $41, $4C, $54, $48, $00 | |
byte $31, $6F, $35, $37, $00 | |
Commands word @Cmd00, @Cmd01, @Cmd02, @Cmd03, @Cmd04, @Cmd05 | |
word @Cmd06, @Cmd07, @Cmd08, @Cmd09, @Cmd10, @Cmd11 | |
word @Cmd12 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have added all of the missing (to be published by 1057 after the convention) Spin code. When used with Propeller Tool, this will produce a byte-for-byte identical EEPROM image to the factory Human badges. If you change the BADGE_TYPE constant to "GOON", it will produce a byte-for-byte identical EEPROM to the factory Goon badge.
Happy hacking!