' =============================================================================== ' ' File....... PyroPack.BS2 ' Purpose.... Prototype This: Firefighter Tech: PyroPack ' Author..... Joe Grand ' ' {$STAMP BS2sx} ' {$PBASIC 2.5} ' {$PORT COM3} ' ' =============================================================================== ' -----[ Program Description ]--------------------------------------------- ' This BASIC Stamp BS2sx (Rev. E) code is for the PyroPack control circuitry ' that performs a number of different functions: ' ' * Interfaces with RFID Reader Module to read RFID tags embedded into the ' PyroPack (or maybe into the firefighter's clothing). This is the crux of ' the Firefighter Identification System of the project and will enable a ' fire fighter to identify other fire fighters in a smoke-filled room. ' In a future revision, you could possibly use Digi XBee wireless modules ' to create a mesh network and communicate information back and forth between ' the firefighters (e.g., mayday call, remaining oxygen level, etc.) ' ' * Interfaces with Keller Preciseline 0328.14903.050500 digital pressure ' transmitter via RS485, which will give us the remaining oxygen level ' in the fire fighter's tank. CRC-16 (Modbus) can be calculated via: ' http://www.lammertbies.nl/comm/info/crc-calculation.html ' ' * Measures Memsic 2125GL Accelerometer and triggers Mayday Call if no ' motion is detected for a given amount of time ' ' * Enables Resc-Hue firefighter emergency lighting system if Mayday Call ' is triggered (supported, but not used in prototype version) ' ' * Provides On-Screen Display interface to convery firefighter status ' and information to the Heads-Up Display ' ' * Provides power to all of the components in the system via a Makita ' 18V LXT Lithium-Ion battery ' ' -----[ I/O Definitions ]------------------------------------------------- Bob_SOUT PIN 5 ' BOB-4-H Video On-Screen Display, INPUT from BOB Bob_SIN PIN 11 ' OUTPUT to BOB RFID_SOUT PIN 0 ' RFID Reader module, serial from reader RFID_Enable PIN 2 ' active LOW Memsic_Xin PIN 14 ' X pulse input from Memsic 2125 accelerometer Memsic_Yin PIN 13 ' Y pulse input Keller_RT PIN 10 ' Receive/Transmit line (HIGH for TX, LOW for RX) Keller_RX PIN 8 ' Data RX: FROM Keller pressure transmitter via LTC485 TO BS2 Keller_TX PIN 9 ' Data TX: TO Keller pressure transmitter via LTC485 FROM BS2 TIC_Enable PIN 6 ' Electronic Power Control (EPC) from Thermal Eye 3600AS OEM module (active LOW) SysReady PIN 1 RescHueEnable PIN 4 ' HIGH to enable Resc-Hue lighting system ' -----[ Constants ]------------------------------------------------------- #SELECT $STAMP #CASE BS2, BS2E, BS2PE T1200 CON 813 T2400 CON 396 T4800 CON 188 T9600 CON 84 T19K2 CON 32 T38K4 CON 6 #CASE BS2SX, BS2P T1200 CON 2063 T2400 CON 1021 T4800 CON 500 T9600 CON 240 T19K2 CON 110 T38K4 CON 45 #CASE BS2PX T1200 CON 3313 T2400 CON 1646 T4800 CON 813 T9600 CON 396 T19K2 CON 188 T38K4 CON 84 #ENDSELECT SevenBit CON $2000 Inverted CON $4000 Open CON $8000 ' BOB-4-H On-Screen Display BOB_Baud CON T19K2 csi1 CON 27 'Control Sequence Introducer = ESC,[ csi2 CON 91 ' Accelerometer HiPulse CON 1 ' measure high-going pulse LoPulse CON 0 'SampleDelay CON 500 AlarmLevel CON 30 ' in seconds XLimit CON 5 ' x motion max YLimit CON 5 ' y motion max ' Keller Preciseline pressure transmitter Keller_Baud CON T9600 DevAddr CON 1 ' device address FuncMODBUS CON 3 FuncReadScalingValues CON 30 FuncWriteScalingValues CON 31 FuncInitialize CON 48 FuncProgramBusAddress CON 66 FuncReadSerialNumber CON 69 FuncReadValueFP CON 73 FuncReadValueInt CON 74 FuncZero CON 95 FuncReadConfigurations CON 100 ' RFID RFID_Baud CON T2400 ' Math routine constants dv CON 6895 ' dv<65536 (Pascals / 6895 = ~PSI) A CON 9 ' A=65536/dv B CON 3480 ' B=65536//dv, the remainder from division A C CON 33086 ' C= B/dv*65536 ' -----[ Variables ]------------------------------------------------------- ' Only 26 Bytes of RAM available in BS2 family idx VAR WORD ' loop counter, rfid tag byte index ' RFID Reader module tagNum VAR BYTE ' from EEPROM table char VAR BYTE ' character from table ' Memsic 2125GL Accelerometer moTimer VAR BYTE ' motion timer xCal VAR WORD ' x calibration value yCal VAR WORD ' y calibration value xMove VAR WORD ' x sample yMove VAR WORD ' y sample xMovePrev VAR WORD ' previous x sample yMovePrev VAR WORD ' previous y sample 'Keller Preciseline pressure transmitter buffer VAR BYTE(9) ' transmit/receive buffer 'wx VAR Word ' most significant word 'wy VAR Word ' least significant 'rm VAR Byte ' remainder from division ' Math variables (for test calculations) 'q1 VAR Word ' output, quotient, z/divisor 'q0 VAR Word ' -----[ EEPROM Data ]----------------------------------------------------- ' valid tags ' 8 tags per person - front, back, left shoulder, right shoulder, and wherever else we decide to put them ' since we don't have enough RAM for a 10-byte buffer, we're only looking at 9 characters for the tag's unique ID ' and ignoring the first digit which, in our case, is a 0. ' Zoz Tag1 DATA "4162B9970" Tag2 DATA "4162B9F45" Tag3 DATA "4162BB550" Tag4 DATA "4162BAC57" Tag5 DATA "4162BA7C4" Tag6 DATA "4162B9962" Tag7 DATA "4162B9F50" Tag8 DATA "4162BA0EE" ' Terry Tag9 DATA "4162B954E" Tag10 DATA "4162B9AF6" Tag11 DATA "4162BB6EC" Tag12 DATA "4162BA13A" Tag13 DATA "4162BADC4" Tag14 DATA "4162B917C" Tag15 DATA "4162BB2EC" Tag16 DATA "4162B8FCE" ' North Tag17 DATA "4162BB504" Tag18 DATA "4162BA339" Tag19 DATA "4162B9D8D" Tag20 DATA "4162BADA3" Tag21 DATA "4162BB406" Tag22 DATA "4162BA343" Tag23 DATA "4162BABB3" Tag24 DATA "4162BB0C6" LastTag CON 24 Name0 DATA "GRAND", 0 ' Any tag not listed in above table Name1 DATA "ZOZ ", 0 Name2 DATA "TERRY", 0 Name3 DATA "NORTH", 0 ' -----[ Initialization ]-------------------------------------------------- Setup: HIGH TIC_Enable ' enable Thermal Imaging Camera PAUSE 1000 DEBUG CLS, "Prototype This PyroPack!", CR, CR ' setup on-screen display parameters ' set display to 480 x 288, clear display settings and screen, select font, select inverse text SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "20;3v", csi1,csi2, "0m", csi1,csi2, "2J", csi1,csi2, "5z", csi1,csi2, "7m"] ' draw filled white square for background SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "0;165.r", csi1,csi2, "390;165+r", csi1,csi2, "390;288+r", csi1,csi2, "0;288+r", csi1,csi2, "!r", csi1,csi2, "#r"] GOSUB Memsic_Initialize ' initialize and calibrate accelerometer GOSUB Keller_Initialize ' initialize Keller pressure transmitter LOW TIC_Enable ' enable Thermal Imaging Camera LOW RescHueEnable ' disable RescHue line/mayday alarm HIGH RFID_Enable ' turn off RFID reader HIGH SysReady ' the system's ready to go! DEBUG "System ready!", CR, CR ' -----[ Program Code ]---------------------------------------------------- Main: GOSUB Read_RFID GOSUB Read_Accelerometer GOSUB Read_Pressure_Gauge DEBUG CR GOTO Main END ' -----[ Subroutines ]----------------------------------------------------- Read_RFID: LOW RFID_Enable ' activate the reader SERIN RFID_SOUT, RFID_Baud, 1500, RFID_Done, [WAIT($0A, $30), STR buffer\9] ' wait for hdr + ID HIGH RFID_Enable ' deactivate reader 'Show_ID: ' DEBUG "Tag Unique ID: " ' FOR idx = 0 TO 8 ' DEBUG buffer(idx) ' NEXT ' DEBUG CR Check_List: FOR tagNum = 1 TO LastTag ' scan through known tags FOR idx = 0 TO 8 ' scan bytes in tag READ (tagNum - 1 * 9 + idx), char ' get tag data from table IF (char <> buffer(idx)) THEN Bad_Char ' compare tag to table NEXT GOTO Tag_Found ' all bytes match! Bad_Char: ' try next tag NEXT Bad_Tag: tagNum = 0 Tag_Found: GOSUB Show_Name ' print name RETURN RFID_Done: SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;1H", " "] ' clear RFID info after delay RETURN Read_Accelerometer: ' Check accelerometer ' Monitors X and Y inputs from Memsic 2125 and will trigger alarm if ' continuous motion is detected beyond the threshold period. GOSUB Get_Accel_Data ' read inputs xMove = ABS (xMove - xCal) ' check for motion yMove = ABS (yMove - yCal) DEBUG "X: ", DEC3 xMove, " Y: ", DEC3 yMove, CR ' adjust measurements if we're below the limit to avoid any negative values for the next comparison IF (xMovePrev < XLimit) THEN xMovePrev = XLimit IF (yMovePrev < YLimit) THEN yMovePrev = YLimit ' if the person is moving around... IF (xMove < xMovePrev - XLimit) OR (yMove < yMovePrev - YLimit) OR (xMove > xMovePrev + XLimit) OR (yMove > yMovePrev + YLimit) THEN SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;11H", " "] 'position cursor, row;column moTimer = 0 ' clear motion timer ELSE ' otherwise, we're measuring no movement, so update the timer moTimer = moTimer + 1 ' update motion timer IF (moTimer > AlarmLevel) THEN 'HIGH RescHueEnable ' enable Resc-Hue light by triggering relay ' notify firefighter that a mayday call has been triggered SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;11H", "MAYDAY"] 'position cursor, row;column DEBUG "ALARM!", CR ENDIF ENDIF RETURN Read_Pressure_Gauge: ' read pressure transmitter via RS485 buffer(0) = $FF GOSUB Keller_Get_Pressure IF (buffer(4) = $00 AND buffer(0) <> $FF) THEN ' make sure we have no errors 'wx.HIGHBYTE = buffer(0) ' pre-load value from pressure transmitter in order to display in decimal format 'wx.LOWBYTE = buffer(1) 'wy.HIGHBYTE = buffer(2) 'wy.LOWBYTE = buffer(3) 'DEBUG "Pressure = $", HEX4 wx, HEX4 wy, CR, CR ' display remaining air in tank (percentage of max. 3000PSI) on screen and in debug terminal DEBUG "Pressure = $", HEX2 buffer(0), HEX2 buffer(1), HEX2 buffer(2), HEX2 buffer(3), CR ' show raw pressure value SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;21H", "AIR "] 'position cursor, row;column ' budget way of detecting approximate percentage of air remaining in tank ' simple table lookup in 5% increments IF (buffer(0) = $00 AND buffer(1) < $0F) THEN SEROUT Bob_SIN, BOB_Baud, [" 0%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $1F) THEN SEROUT Bob_SIN, BOB_Baud, [" 5%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $2F) THEN SEROUT Bob_SIN, BOB_Baud, ["10%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $3F) THEN SEROUT Bob_SIN, BOB_Baud, ["15%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $4F) THEN SEROUT Bob_SIN, BOB_Baud, ["20%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $5F) THEN SEROUT Bob_SIN, BOB_Baud, ["25%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $6F) THEN SEROUT Bob_SIN, BOB_Baud, ["30%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $7F) THEN SEROUT Bob_SIN, BOB_Baud, ["35%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $8F) THEN SEROUT Bob_SIN, BOB_Baud, ["40%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $9F) THEN SEROUT Bob_SIN, BOB_Baud, ["45%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $AF) THEN SEROUT Bob_SIN, BOB_Baud, ["50%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $BF) THEN SEROUT Bob_SIN, BOB_Baud, ["55%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $CF) THEN SEROUT Bob_SIN, BOB_Baud, ["60%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $DF) THEN SEROUT Bob_SIN, BOB_Baud, ["65%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $EF) THEN SEROUT Bob_SIN, BOB_Baud, ["70%"] ELSEIF (buffer(0) = $00 AND buffer(1) < $FF) THEN SEROUT Bob_SIN, BOB_Baud, ["75%"] ELSEIF (buffer(0) = $01 AND buffer(1) < $0C) THEN SEROUT Bob_SIN, BOB_Baud, ["80%"] ENDIF SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;21H", "AIR "] 'position cursor, row;column IF (buffer(0) = $01 AND buffer(1) < $1C) THEN SEROUT Bob_SIN, BOB_Baud, ["85%"] ELSEIF (buffer(0) = $01 AND buffer(1) < $2C) THEN SEROUT Bob_SIN, BOB_Baud, ["90%"] ELSEIF (buffer(0) = $01 AND buffer(1) < $3C) THEN SEROUT Bob_SIN, BOB_Baud, ["95%"] ELSEIF (buffer(0) = $01) THEN ' maximum of 4866psi ($01FFFFFF) SEROUT Bob_SIN, BOB_Baud, ["100%"] ELSEIF (buffer(0) > $01) THEN ' otherwise we must be out of range SEROUT Bob_SIN, BOB_Baud, ["N/A%"] ENDIF ' calculate w/dv, where w=wx:wy, two words 'q1 = wx / dv 'q0 = wx // dv 'rm = ((q0 ** B * B // dv) + (q0 * B) // dv + (wy // dv)) 'q0 = (q0 * A) + (q0 ** C) + (wy / dv) + (rm / dv) 'rm = rm // dv 'buffer(0) = rm ' set the remainder, we don't use this 'wx = q1 'wy = q0 'GOSUB PrintLongDecimal 'DEBUG " PSI)", CR, CR ENDIF RETURN ' Prints name associated with RFID tag Show_Name: ' display firefighter ID information on screen and in debug terminal SEROUT Bob_SIN, BOB_Baud, [csi1,csi2, "14;1H"] 'position cursor, row;column DEBUG DEC tagNum, ": " LOOKUP tagNum, [Name0, Name1, Name1, Name1, Name1, Name1, Name1, Name1, Name1, Name2, Name2, Name2, Name2, Name2, Name2, Name2, Name2, Name3, Name3, Name3, Name3, Name3, Name3, Name3, Name3], idx ' point to first character (8 tags per person) DO READ idx, char ' read character from name IF (char = 0) THEN EXIT ' if 0, we're done DEBUG char ' otherwise print it SEROUT Bob_SIN, BOB_Baud, [char] ' display on screen idx = idx + 1 ' point to next character LOOP DEBUG CR RETURN Memsic_Initialize: moTimer = 0 ' clear motion timer Read_Cal_Values: PULSIN Memsic_Xin, HiPulse, xCal ' read calibration values PULSIN Memsic_Yin, HiPulse, yCal xCal = xCal / 10 ' filter for noise & temp yCal = yCal / 10 DEBUG "xCal = ", DEC3 xCal, " yCal = ", DEC3 yCal, CR RETURN ' Sample and filter accelerometer inputs Get_Accel_Data: xMovePrev = xMove yMovePrev = yMove PULSIN Memsic_Xin, HiPulse, xMove ' take first reading PULSIN Memsic_Yin, HiPulse, yMove xMove = xMove / 10 ' filter for noise & temp yMove = yMove / 10 'PAUSE SampleDelay RETURN Keller_Initialize: DEBUG "Initializing Keller Pressure Transmitter...", CR buffer(0) = DevAddr buffer(1) = FuncInitialize buffer(2) = $34 ' CRC16_H buffer(3) = $00 ' CRC16_L KellerInit: HIGH Keller_RT ' put LTC485 into transmit mode PAUSE 10 SEROUT Keller_TX, Keller_Baud, [STR buffer\4] LOW Keller_RT ' put LTC485 into receive mode SERIN Keller_RX, Keller_Baud, 16, KellerInit, [WAIT(buffer(0), buffer(1)), STR buffer\8] ' if we don't get a response within 6.4ms (16 * 0.4), repeat query DEBUG "Keller Init (Raw): " FOR idx = 0 TO 7 DEBUG HEX2 buffer(idx), " " NEXT DEBUG CR RETURN Keller_Get_Pressure: 'DEBUG "Getting Pressure.." buffer(0) = DevAddr buffer(1) = FuncReadValueInt buffer(2) = $01 ' pressure sensor 1 buffer(3) = $A0 ' CRC16_H (Int) buffer(4) = $D6 ' CRC16_L (Int) KellerPressure: 'DEBUG "." HIGH Keller_RT ' put LTC485 into transmit mode PAUSE 10 SEROUT Keller_TX, Keller_Baud, [STR buffer\5] LOW Keller_RT ' put LTC485 into receive mode SERIN Keller_RX, Keller_Baud, 16, KellerPressure, [WAIT(buffer(0), buffer(1)), STR buffer\7] ' if we don't get a response within 6.4ms (16 * 0.4), repeat query 'DEBUG "Pressure Resp (Raw): " 'FOR idx = 0 TO 6 ' DEBUG HEX2 buffer(idx), " " 'NEXT 'DEBUG CR RETURN 'PrintLongDecimal: ' -- printout routine (prints a 4-byte (32-bit) value as decimal), digits stored in spRAM ' FOR idx=4 TO 0 ' 5 bytes can hold 10 digits ' temp=wx//100 ' high remainder ' wx=wx/100 ' high word of quotient ' rm=((temp*36//100)+(wy//100)) ' remainder calc ' wy=(temp*655)+(temp*36/100)+(wy/100)+(rm/100) 'low word of quotient ' rm=rm//100 ' final remainder ' PUT idx,rm ' store remainder ' NEXT ' ix next digits ' ' -- printout routine, digits stored in spRAM ' rm=0 ' nothing printed yet ' FOR idx=0 TO 4 ' GET idx,temp ' rm=temp MAX 1+(idx/4)+rm+rm ' 0 until 1st non-zero byte ' ' or until last byte ' ' >1 after first non-zero byte ' BRANCH rm,[showdub2,showdub1] ' DEBUG DEC2 temp ' end up here to print leading zeros ' GOTO showdub2 ' showdub1: ' branch here to print without leading zeros ' DEBUG DEC temp ' showdub2: ' branch here to print nothing ' NEXT ' RETURN ' -----[ END OF FILE ]-----------------------------------------------------