' {$STAMP BS2} ' {$PBASIC 2.5} 'ver after making 6feb08 bu 'S2SysServer2 (There is no "Server1"... that was "Perif1" 'Second attempt at S2Sys... "Server" program (previously 'known as peripheral) '============ Init: 'k5datum and k6datum determine what datum is sent when ' buttons in test rig are pressed. Essential to DEMO, ' but not to core of S2Sys 'For simple pushbutton-on-lines 5 & 6 scheme... k5datum CON 6 k6datum CON 7 'For 2x3 matrix keyboard with outputs over 2 & 3, ' inputs on 4,5 & 6... kAdatum CON 1 'The assignments are arbirary and will kBdatum CON 5 'depend on your keyboard and wants kCdatum CON 3 kDdatum CON 0 kEdatum CON 4 kFdatum CON 2 'S2toH will be on P0, so... DIR0=1 'Set P0 for output from Stamp... it will ' carry S2toClient, messages to client. OUT0=1 'To say "no data waiting in server". DIR7=0 'Set P7 for input to Stamp... it will ' carry S2frClient, messages from client. 'There is no reason that S2toClient or S2frClient couldn't ' be on other data lines. These just happen to be ' the lines chosen this time. S2pHalfBit CON 80 'Sets the speed of the serial link. 'A similar setting must be the same in the software 'running on the host. Half of the time a given bit 'in the serial stream is asserted. The "p" in the 'name is for "protocol" so that all varialble 'relating to the protocol share a prefix S2OneBit CON S2pHalfBit*2 S2pDataBits CON 8 'Number of bits in each word, counting 'only the data. Any error detection/correction bits 'will be counted separately. (At the time of writing, 'no error detect bits have been incorporated.... but 'things have been done so that they can be easily.) bS2SysDatum VAR Byte 'A place to put the byte to be sent bTmpError VAR Byte 'A place to pass transient flags 'settings not related to basics of S2Sys... DIR1=1 'Set P1 as output.. to drive local LED DIR2=1 'Set P2 as output... for matrix. Also drives an LED DIR3=1 'Set P2 as output... for matrix OUT1=0 OUT2=0 DIR6=0 'P6: "keyboard" input- button OR matrix schemes DIR5=0 'P5: "keyboard" input- button OR matrix schemes DIR4=0 'P4: matrix scheme only bTmpMatrix VAR Byte 'Tmp store for ReadMatrix routine c1 VAR Byte 'for misc "FOR" loops, etc c2 VAR Word 'for tmp store DataBuffLast CON 5 'Last slot avail in DataBuffer DataBuff VAR Byte(DataBuffLast+1) 'N.B.: If you say Byte(4), then the ' maximum index allowed is 3. (Element 0 exists) Exceed ' the max index and you may encounter data corruption ' without any warning error message. There's no need ' to init the contents of the array. ' N.B. "Byte(4)" creates a DataBuff(0), but NOT a ' DataBuff(4)... DataBuff(3) is the last... I think! DataBuffPointer VAR Byte DataBuffPointer=0 'Points to next avail slot boS2frClientState VAR Bit GOSUB S2toClientHigh 'Made subroutine for easy 'reassignment of data lines to different hardware. 'bTmpError=0 'End of inits.... '================= MainLoop: 'Program must not linger in any subroutine 'GOSUB TryToFetchDatumButtons 'Alternative to... GOSUB TryToFetchDatumMatrix 'Fills bS2SysDatum... if something avail. 'This datum is NOT being fetched over the client/server 'link... THIS datum is coming from whatever feeds 'the server with data to be served. In the case of 'the demo program the data comes from push buttons on 'inputs 5 and 6. 'and fills bTmpError with flag... 0 if datum found; ' 255 flags "no datum found" 'Next, if datum fetched, we must... 'if buffer not already full... ' put it in buffer, ' increment DataBuffPointer '(DataBufferPointer=0 when the buffer is empty) 'bTmpError=0 'debug: This and next simulate Fetch successful 'bS2SysDatum=4 IF bTmpError>0 THEN SkipPutInBuff 'ELSE... 'work next two lines to implement queing.. 'not yet well tested. IF DataBuffPointer>DataBuffLast THEN SkipPutInBuff DataBuff(DataBuffPointer)=bS2SysDatum DataBuffPointer=DataBuffPointer+1 'end ELSE ' DataBuff(0)=bS2SysDatum ' DataBuffPointer=1 SkipPutInBuff: IF DataBuffPointer=0 THEN SkipAhead1 'ELSE.... try to send GOSUB S2toClientLow 'Set "data available" flag. Tells client that 'datum is ready for fetching at the client's 'convenience. Client will signal when it wants 'it by bringing S2frClient low. 'N.B.: It is not likely or necessary that the client will ' respond quickly enough to the "data available" flag to ' provide the "send it" answer in time for it to be picked ' up by the next bit of code in the same pass through the ' server's main loop as that in which the "data available" ' status was asserted. GOSUB CheckS2frClientState 'Sets or clears flag boS2frClientState 'IF DataBuffPointer>0 THEN boS2frClientState=0 'DEBUG<<<<<<<<<<<<<<< IF boS2frClientState=1 THEN SkipAhead1 '(Skips ahead if, following server's establishment 'of "data available" condition, 'S2frClient is not yet saying "send it". But if it IS.... GOSUB SendNShuffle 'see SR 'Now that datum has been sent, clear or set 'S2toClient to say whether another datum is available 'at this time. Note that SendNShuffle left it high, to 'say "Don't ask for another datum yet, even though there 'may be (client won't know at this point) another datum 'in the buffer. I.e. S2toClient should be high at this 'time, regardless of buffer state. 'DataBuffPointer=0' DEBUG <<<<<<<<<<<< 'THERE IS NO NEED to send S2toClient low here, even if ' there is data in the buffer. That will be handled ' in the early part of this level's loop. 'IF DataBuffPointer>0 GOSUB s2toClientLow 'N.B. PBASIC's IF..THEN..ELSE has some easy-to- 'get-wrong block structure rules, and several 'variations. 'End of ELSE try to send. SkipAhead1: GOTO MainLoop 'End of MainLoop '============================ '====== Subroutines follow... s2toClientHigh: 'Put in SR to simplify reassigning hardware 'Set the line high OUT0=1 RETURN s2toClientLow: 'Set the line low OUT0=0 RETURN CheckS2frClientState: 'Sets or clears boS2frClientState 'Put in SR to simplify reassigning hardware IF IN7=1 THEN boS2frClientState=1 ELSE boS2frClientState=0 RETURN TryToFetchDatum2Buttons: 'Parts of this will vary from server to server. 'This version is for reading inputs from two simple ' buttons on lines pulled high by resistors, and tied ' to 0v when button pressed '... BUT: All will fill bS2SysDatum... if anything avail, 'and fill bTmpError with flag... 0 if datum found. 'This routine less than ideal... breaks the "no routine ' should be able to "trap" program" rule... but may be ' something we may be able to get away with. Could cause ' problem if there's data in the queue, the server (hardware ' running this program) has set S2toClient low to say ' "DataAvailable", client invokes its right to ask for ' that data (by making S2frClient low)... and receives ' no reply 'cause server program is trapped in this ' subroutine. ' This routine only "traps" program ' if user presses down and HOLDS an input key. bTmpError=255 'init. Will return this value if no key pressed IF IN5=1 THEN SKIPIn51 bS2SysDatum=k5datum 'Value sent if key-on-5 pressed bTmpError=0 WaitForIN5Release: IF IN5=0 THEN WaitForIn5Release PAUSE(6)'debounce IF IN5=0 THEN WaitForIn5Release PAUSE(4) IF IN5=0 THEN WaitForIn5Release PAUSE(2)'To let host get done, for lines to settle GOTO SkipIn61 SkipIn51: IF IN6=1 THEN SkipIn61 bS2SysDatum=k6datum 'Value sent if key-on-6 pressed bTmpError=0 WaitForIN6Release: IF IN6=0 THEN WaitForIn6Release PAUSE(6)'debounce IF IN6=0 THEN WaitForIn6Release PAUSE(4) IF IN6=0 THEN WaitForIn6Release PAUSE(2)'To let host get done, for lines to settle SkipIn61: RETURN 'End of TryToFetchDatum2Buttons TryToFetchDatumMatrix: 'Parts of this will vary from server to server. 'This version is for reading inputs from a 2x3 matrix... ' 2 columns driven by outputs 2 & 3 of the Stamp, ' by 3 rows feeding inputs 4, 5 and 6. ' Be sure to put the necessary diodes in series between ' the outputs of the Stamp and the matrix column connections. '... BUT: All will fill bS2SysDatum... if anything avail, 'and fill bTmpError with flag... 0 if datum found. 'The routine does not provide rollover reading... if more ' than one key is pressed down, only one will be "seen" 'Because of the way the program works, a very briefly pressed ' key may not be seen. A key pressed and held may be "seen" ' as having been pressed several times. 'A green LED on output 2 will flash briefly during the first ' half of the "read matrix" bTmpError=255 'init. Will return this value if no key pressed bS2SysDatum=255 'FOR NOW flags no datum seen 'Clumsy... there are better ways! OUT2=1 'check 1st column. 'PAUSE(1500)'debug PAUSE(15)'so green LED can be perceived to come on ' And to give 5v time to fully develop on the column bTmpMatrix=IN4 IF bTmpMatrix=0 THEN GOTO TryRow1 bS2SysDatum=0 'NOT bS2SysDatum's final value... temporary code TryRow1: bTmpMatrix=IN5 IF bTmpMatrix=0 THEN GOTO TryRow2 bS2SysDatum=1 TryRow2: bTmpMatrix=IN6 IF bTmpMatrix=0 THEN GOTO TrySecondColumn bS2SysDatum=2 TrySecondColumn: OUT2=0 OUT3=1 'check 2nd column. 'PAUSE(1500)'debug PAUSE(10) ' To give 5v time to fully develop on the column, and ' for all traces of 5v to decay from column0 bTmpMatrix=IN4 IF bTmpMatrix=0 THEN GOTO TryRow1b bS2SysDatum=3 'NOT bS2SysDatum's final value... temporary code TryRow1b: bTmpMatrix=IN5 IF bTmpMatrix=0 THEN GOTO TryRow2b bS2SysDatum=4 TryRow2b: bTmpMatrix=IN6 IF bTmpMatrix=0 THEN GOTO EndTryRowsNCols bS2SysDatum=5 EndTryRowsNCols: IF bS2SysDatum<255 THEN bTmpError=0 'Set things up to say '"Datum found" OUT3=0 'Restore to inactive. 'There's now a number in bSysDatum... either 255 if 'no keypress was detected, or 0,1,2...5 if a key was 'seen depressed. 'Now "translate" the key to the return code of choice... '... note that 255 ceases to be a rogue value at this point. 'Note to self: Make sure case "works", in particular if on ' entering the statement with bSysDatum=1 and kBdatum=3, then ' be sure that bSysDatum doesn't end up set to kDdatum bTmpMatrix=bS2SysDatum 'may not be necessary... but does no harm! SELECT bTmpMatrix CASE 0 bS2SysDatum=kAdatum CASE 1 bS2SysDatum=kBdatum CASE 2 bS2SysDatum=kCdatum CASE 3 bS2SysDatum=kDdatum CASE 4 bS2SysDatum=kEdatum CASE 5 bS2SysDatum=kFdatum CASE ELSE bS2SysDatum=255 ENDSELECT 'DEBUG DEC bS2SysDatum," " RETURN 'End of TryToFetchDatumMatrix SendNShuffle: 'Send datum from bS2SysDatum, and shuffle the data in the buffer, ' and adjust DataBuffPointer GOSUB SendDatum GOSUB Shuffle 'Next: S2toClient will be cleared or set in main block, 'to post signal to client as to whether more data available 'from buffer RETURN SendDatum: 'First send start Bit- GOSUB s2toClientHigh PAUSE(S2OneBit) 'Then send the data 'CONVERT TO.... TO ALLOW DIFFERNT £ OF databits.. 'FOR c1=1 TO S2pDataBits 's2toClientLow OR high 'PAUSE(S2OneBit) 'Next bS2SysDatum=DataBuff(DataBuffPointer-1) 'TMP crude version... but it works! GOSUB S2SendBit7 PAUSE(S2OneBit) GOSUB S2SendBit6 PAUSE(S2OneBit) GOSUB S2SendBit5 PAUSE(S2OneBit) GOSUB S2SendBit4 PAUSE(S2OneBit) GOSUB S2SendBit3 PAUSE(S2OneBit) GOSUB S2SendBit2 PAUSE(S2OneBit) GOSUB S2SendBit1 PAUSE (S2OneBit) GOSUB S2SendBit0 PAUSE(S2OneBit) '... and set S2toClient high after last bit, because 'otherwise client will "see" "DataAvailableFromServer." 'Even if there is more data in the buffer, we don't want 'to tell the client yet, because we need time to tie things 'off. GOSUB S2toClientHigh 'S2toClient will be re-cleared in a moment, 'at higher level, after call of Shuffle, 'if further data availablein server's queue '==== 'Little extra bit... not central to S2Sys... here 'to help with debugging. MAY have an effect, but 'doesn't, I don't THINK. ' 'After Datum sent, wink not-essential-to-S2Sys-LED on 'server to say "Datum Sent" OUT1=1 PAUSE(300) OUT1=0 RETURN Shuffle: 'Beware: Approach is simple, and fine for small buffers. 'Larger buffers might need handling differently... a 'fancier pointer scheme would avoid the need for moving 'everything down in the array. 'General points... ' DataBuffLast CON 3, then ' DataBuff VAR Byte(DataBuffLast+1) ' DOES create elements 0,1,2 and 3 ' And BEWARE: The compiler will quite happily accept ' something like bS2SysDatum(c1-1)=bS2SysDatum(c1) ' when bS2SysDatum is a mere byte type datum, not ' an array. The result? Not pretty! Other variables ' get corrupted. FOR c1=1 TO DataBuffLast DataBuff(c1-1)=DataBuff(c1) 'DEBUG DEC c1 NEXT 'DataBuffPointer=0' 'We wouldn't be here if pointer=0, so the following is safe.. DataBuffPointer=DataBuffPointer-1 RETURN RandomBit: RANDOM c2 IF c2>32000 THEN GOSUB s2toClientLow ELSE GOSUB s2toClientHigh RETURN 'Following routine set crude and space wasting... but simple! S2SendBit7: IF (bS2SysDatum & 128) =128 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit6: IF (bS2SysDatum & 64) = 64 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit5: IF (bS2SysDatum & 32) = 32 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit4: IF (bS2SysDatum & 16) = 16 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit3: IF (bS2SysDatum & 8) = 8 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit2: IF (bS2SysDatum & 4) = 4 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit1: IF (bS2SysDatum & 2) = 2 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN S2SendBit0: IF (bS2SysDatum & 1) =1 THEN GOSUB s2toClientHigh ELSE GOSUB s2ToClientLow RETURN