# ########################################################################## # # Copyright (c) 2000-2004 by Wayne C. Gramlich & William T. Benson. # All rights reserved. # # This is the code that implements the Switch8 RoboBrick. Basically # it just waits for commands that come in at 2400 baud and responds # to them. See: # # http://web.gramlich.net/projects/robobricks/switch8/index.html # # for more details. # # ########################################################################## library $pic12f629 library clock4mhz library bit_bang package pdip pin 1 = power_supply pin 2 = gp5_out, name = serial_out pin 3 = gp4_in, name = serial_in pin 4 = gp3_in, name = in3 pin 5 = gp2_out, name = out2 pin 6 = gp1_out, name = out1 pin 7 = gp0_out, name = out0 pin 8 = ground # Define some globals: global inputs byte global complement byte # Interrupt masks: global interrupt_enable bit global interrupt_pending bit global falling byte global high byte global low byte global raising byte global command_previous byte global command_last byte global sent_previous byte global sent_last byte procedure main arguments_none returns_nothing # This is the main program that is responsible for processing commands # from the master. local command byte local glitch byte local id_index byte local result byte local temp byte complement := 0 interrupt_enable := 0 interrupt_pending := 0 falling := 0 high := 0 low := 0 raising := 0 glitch := 0 id_index := 0 loop_forever command := byte_get() switch command >> 6 case 0 # Command = 00xx xxxx: switch command >> 3 case 0 # Command = 0000 0xxx: switch command & 7 case 0 # Read Inputs (Command = 0000 0000): call byte_put(inputs ^ complement) case 1 # Read Complement Mask (Command = 0000 0001): call byte_put(complement) case 2 # Read Low Mask (Command = 0000 0010): call byte_put(low) case 3 # Read High Mask (Command = 0000 0011): call byte_put(high) case 4 # Read Raising Mask (Command = 0000 0100): call byte_put(raising) case 5 # Read Falling Mask (Command = 0000 0101): call byte_put(falling) case 6, 7 { do_nothing case 1 # Command = 0000 1xxx: switch command & 7 case 0 # Read Raw (Command = 0000 1000): call byte_put(inputs) case 1 # Read Complement (Command = 0000 1001): complement := byte_get() case 2 # Read Low (Command = 0000 1010): low := byte_get() case 3 # Read High (Command = 0000 1011): high := byte_get() case 4 # Read Raising (Command = 0000 1100): raising := byte_get() case 5 # Read Falling (Command = 0000 1101): falling := byte_get() case 6, 7 do_nothing case 2, 3, 4, 5, 6, 7 { do_nothing case 1, 2 do_nothing case 3 # Command = 11xx xxxx: switch (command >> 3) & 7 case 0, 1, 2, 3, 4 # Command = 1100 xxxx or 1110 0xxx: do_nothing case 5 # Read Interrupt Bits (Command = 1110 1111): if (command & 7) = 7 # Return Interrupt Bits: result := 0 if interrupt_enable result := result | 2 if interrupt_pending result := result + 1 call byte_put(result) case 6 # Shared Interrupt commands (Command = 1111 0xxx): switch command & 7 case 0, 1, 2, 3 # Set interrupt bits (Command = 1111 00ep): interrupt_enable := command@1 interrupt_pending := command@0 case 4, 5 # Set Interrupt Pending (Command = 1111 010p): interrupt_pending := command@0 case 6, 7 # Set Interrupt Enable (Command = 1110 011e): interrupt_enable := command@0 case 7 # Shared commands (Command = 1111 1xxx): switch command & 7 case 0 # Clock Decrement (Command = 1111 1000): $osccal := $osccal - $osccal_lsb case 1 # Clock Increment (Command = 1111 1001): $osccal := $osccal + $osccal_lsb case 2 # Clock Read (Command = 1111 1010): call byte_put($osccal) case 3 # Clock Pulse (Command = 1111 1011): call byte_put(0) case 4 # ID Next (Command = 1111 1100): temp := 0 if id_index < id.size temp := id[id_index] id_index := id_index + 1 call byte_put(temp) case 5 # ID Reset (Command = 1111 1101): id_index := 0 case 6 # Glitch Read (Command = 1111 1110): call byte_put(glitch) glitch := 0 case 7 # Glitch (Command = 1111 1111): if glitch != 0xff glitch := glitch + 1 procedure delay arguments_none returns_nothing exact_delay delay_instructions # This procedure delays for 1 third of a bit time. It is responsible # for reading the inputs and dealing with interrupts. local changed byte local previous byte local not_inputs byte local counter byte watch_dog_reset # Clear the select bits: $gpio := $gpio & 0xf8 inputs := 0 if in3 inputs@7 := 1 out0 := 1 if in3 inputs@6 := 1 out1 := 1 if in3 inputs@4 := 1 out0 := 0 if in3 inputs@5 := 1 out2 := 1 if in3 inputs@1 := 1 out0 := 1 if in3 inputs@0 := 1 out1 := 0 if in3 inputs@2 := 1 out0 := 0 if in3 inputs@3 := 1 out2 := 0 # Deal with interrupts: not_inputs := inputs ^ 0xff changed := inputs ^ previous if (low & not_inputs) | (high & inputs) | (changed & inputs & raising) | (changed & not_inputs & falling) != 0 interrupt_pending := 1 # Remember current inputs for next time around: previous := inputs # Send an interrupt if interrupts are enabled: if interrupt_pending && interrupt_enable # Shove serial out to low to indicate an interrupt: interrupt_enable := 0 serial_out := 0 constant zero8 = "\0,0,0,0,0,0,0,0\" constant vendor_name = "\15\Gramlich&Benson" constant module_name = "\8\Switch8A" string id = "\1,0,18,0,0,0,0,0\" ~ zero8 ~ zero8 ~ module_name ~ vendor_name