;this have to be called after setting
;maxvalue in config1.
;Have a look, that we have to scan up to 24 bits
;If we do this for 3 positions ( max,cur,target)
;in STEP_WORK we go up to over 800 cycles.
;so we have here to scan the maxvalue, and build
;a offset once a time after maxvalue is set.
;this offset, then is used by scan_direction
;Because this is not any time-sensitive stuff
;there is no calculation of cycles, and the
;code is more for good overviewing.
;after this:
;offsetbyte contains nr of byte containing the highest bit of maxval
;offsetbit  contains nr to rol
;spec_flags.OFFSET_ROLLEFT is set, or not to show direction to rol 
init_scanoffset

	BCF		spec_flags,OFFSET_ROLLEFT,AC

	MOVLW	0x03
	MOVWF	offsetbyte,AC

	MOVF	maxpos3,W,AC
	BZ		inioffb3empty

	BTFSC	maxpos3,0x07,AC
	GOTO	initscanoffbit7
	BTFSC	maxpos3,0x06,AC
	GOTO	initscanoffbit6
	BTFSC	maxpos3,0x05,AC
	GOTO	initscanoffbit5
	BTFSC	maxpos3,0x04,AC
	GOTO	initscanoffbit4
	BTFSC	maxpos3,0x03,AC
	GOTO	initscanoffbit3
	BTFSC	maxpos3,0x02,AC
	GOTO	initscanoffbit2
	BTFSC	maxpos3,0x01,AC
	GOTO	initscanoffbit1
	BTFSC	maxpos3,0x00,AC
	GOTO	initscanoffbit0

inioffb3empty
	DECF	offsetbyte,1,AC
inioffb3

	MOVF	maxpos2,W,AC
	BZ		inioffb2empty

	BTFSC	maxpos2,0x07,AC
	GOTO	initscanoffbit7
	BTFSC	maxpos2,0x06,AC
	GOTO	initscanoffbit6
	BTFSC	maxpos2,0x05,AC
	GOTO	initscanoffbit5
	BTFSC	maxpos2,0x04,AC
	GOTO	initscanoffbit4
	BTFSC	maxpos2,0x03,AC
	GOTO	initscanoffbit3
	BTFSC	maxpos2,0x02,AC
	GOTO	initscanoffbit2
	BTFSC	maxpos2,0x01,AC
	GOTO	initscanoffbit1
	BTFSC	maxpos2,0x00,AC
	GOTO	initscanoffbit0

inioffb2empty
	DECF	offsetbyte,1,AC
inioffb2

	MOVF	maxpos1,W,AC
	BZ		inioffb1empty

	BTFSC	maxpos1,0x07,AC
	GOTO	initscanoffbit7
	BTFSC	maxpos1,0x06,AC
	GOTO	initscanoffbit6
	BTFSC	maxpos1,0x05,AC
	GOTO	initscanoffbit5
	BTFSC	maxpos1,0x04,AC
	GOTO	initscanoffbit4
	BTFSC	maxpos1,0x03,AC
	GOTO	initscanoffbit3
	BTFSC	maxpos1,0x02,AC
	GOTO	initscanoffbit2
	BTFSC	maxpos1,0x01,AC
	GOTO	initscanoffbit1
	BTFSC	maxpos1,0x00,AC
	GOTO	initscanoffbit0

inioffb1empty
	DECF	offsetbyte,1,AC
inioffb1

	MOVF	maxpos0,W,AC
	BZ		initscanoffsetend ;this should never be happens, all is 0

	BTFSC	maxpos0,0x07,AC
	GOTO	initscanoffbit7
	BTFSC	maxpos0,0x06,AC
	GOTO	initscanoffbit6
	BTFSC	maxpos0,0x05,AC
	GOTO	initscanoffbit5
	BTFSC	maxpos0,0x04,AC
	GOTO	initscanoffbit4

	GOTO	initscanoffbx ;this is the case, if lownibble of byte 0
						  ;contains a poor number of max 16,
                  		  ;or less, or nothing.

;---------------
	;now, we have to modify offsetbit, to a loopvalue
    ;which also shows the direction, where to rol to
    ;we need the highest 4 bits, for having 16 segments.
	;offsetbyte contains number of byte, containing
	;the highest bit.

	;offsetbit  has to set to nr to rol
	;spec_flags.OFFSET_ROLLEFT is to set, when direction is left

initscanoffbit0
	;rol this, and next byte ( if any ) 3 times to left
	MOVLW	0x03
	MOVWF	offsetbit,AC
	BSF		spec_flags,OFFSET_ROLLEFT,AC
	GOTO	initscanoffsetend
initscanoffbit1
	;rol this, and next byte ( if any ) 2 times to left
	MOVLW	0x02
	MOVWF	offsetbit,AC
	BSF		spec_flags,OFFSET_ROLLEFT,AC	
	GOTO	initscanoffsetend
initscanoffbit2
	;rol this, and next byte ( if any ) 1 times to left
	MOVLW	0x01
	MOVWF	offsetbit,AC
	BSF		spec_flags,OFFSET_ROLLEFT,AC		
	GOTO	initscanoffsetend
initscanoffbit3
	;no work necessary, the lownibble contains all what we want
	MOVLW	0x00
	MOVWF	offsetbit,AC
	GOTO	initscanoffsetend
initscanoffbit4
	;rol this byte 1 times to right
	MOVLW	0x01
	MOVWF	offsetbit,AC
	GOTO	initscanoffsetend
initscanoffbit5
	;rol this byte 2 times to right
	MOVLW	0x02
	MOVWF	offsetbit,AC
	GOTO	initscanoffsetend
initscanoffbit6
	;rol this byte 3 times to right
	MOVLW	0x03
	MOVWF	offsetbit,AC
	GOTO	initscanoffsetend
initscanoffbit7
	;rol complete high-nibble to right, or use it directly
	MOVLW	0x04
	MOVWF	offsetbit,AC
	GOTO    initscanoffsetend
initscanoffbx
	MOVLW	0x00
	MOVWF	offsetbit,AC
initscanoffsetend
	RETURN
	;now, offsetbyte should contain the nr of first byte containing
	;a valid value, and offsetbit the nr of the first bit which is 1















;############# THE COMMAND WORK #######################

;Note: All positons, set by s1,s2,s3,s4 or receives during
;r1,r2,r3,r4 depening on motors are handled as 1/32 fullstepvalues.

;Note: The frequency used to do motorstepping, and/or encoderscanning
;can be handled in two different ways:
;One is to set the flag INT_AS_FRQ.
;This means , every spi-int occures STEP_WORK will be called.
;Have a look for that you can send a sequence in two differnet ways,
;byte per byte, every effecting an interrupt, or all in one sequence,
;where the first byte received starts the interrupt.
;(Handling three boards, all using the same CS,and clock-line,
;ends in 21 bytes to handle, and 3 interrupts, if all send in one
;sequence. - Thats ends in a max. possible frequence of 7200 Hz ).
;The second way to handle frequencies is to use TIMER_AS_FRQ, and
;using a 16 bit timervalue.
;For all handable ways additionally a counter (steplp) is available,
;which is decremented every STEP_WORK. So with this you have additionally
;the possibility to split the frequency.
;All of this provide the feature, to set frequencies in a very sensible way.
;( A value of 0 for steplp means, no additionally splitting ).
;The encoderwork ignores steplp completely, means encoderscanning is every
;time done, STEP_WORK is called, if a step will be handled, or not.
;
;Note: The programloop of elmot-software only handles the testing for
;commands. If you use INT_HANDLES_CMD the programloop, has no effect.
;
;
;commandbyte
;this is handled by program-loop, using CMD_WORK
;or directly by interrupt, also using CMD_WORK
;(if INT_HANDLES_CMD is set )
;first byte of sequence ( cmd-byte )
;valid commands    ( higher bits overrides lower bits )
;7 6 5 4 3 2 1 0   ( bits 0,1,2 not used = address )
;------------------------------------------------------
;0 0 0 0 0 a a a   NOP Useful for nothing, reducing performance, or getting current pos.
;                  s1,s2,s3,s4,s5,s6 not handled
;                  r1,r2,r3,r4 contains current position r5,r6 current encoderpos
;
;
;
;0 0 0 0 1 a a a   set TARGET, normally the mostly used command.
;
;                  s1,s2,s3,s4 must contain new "target" positon,
;                              reflecting a 1/32 fullstepvalue.
;
;				   s5 depends on the settings on flags in s6
;     
;                  s6 This flag-bits steering additional the functionality
;
;                  s6.7 STEP_ON         ;generally switch for calling STEP_WORK
;                                       ;if this is not set, STEP_WORK
;                                       ;only do its encoderwork, but nothing with the motors.
;                                       ;This flag is also internally cleared, whenever
;                                       ;current position is equal target position.
;
;
;                  s6.6 RESTART_FRQ     ;This is also useful, for a stop after move,
;                                       ;If this is 1, all counters, or timers, will
;                                       ;be set to their starting conditions.
;                                       ;Means, steplpcounter will be reset to steplp
;                                       ;If TIMER_AS_FRQ is set timer will be restarted.
;                                       ;After restarting the flag is internally cleared.
;                                       ;This flag is also to use generally with the first command,
;                                       ;if TIMER_AS_FRQ is used, to start it.
;
;                  s6.5 DONT_IGNORES5   ;Dont ignore content of s5
;                                       ;If this is 1, s5 will be used, depending on s6.4
;                                       ;If 0, s6.4, and s5 are ignored.
;                                       ;This flag is also internally cleared, directly
;                                       ;after setting content s5.
;                                       ;(If your next sequence sets this flag again,
;                                       ;also content will be set again ).
;
;                  s6.4 CONTENT_S5      ;content of s5, if s6.5 is set
;                                       ;if this is 1 new steplp will be set from s5
;                                       ;(if INT_AS_FRQ, or additional to TIMER_AS_FRQ)
;                                       ;if this is 0 the low-byte for the timervalue
;                                       ;will be set from s5
;                                       ;(For case TIMER_AS_FRQ is used )
;
;
;                  s6.3 reserved, currently not used
;
;                  s6.2 reserved, currently not used
;
;                  s6.1 reserved, currently not used
;
;                  s6.0 reserved, currently not used
;
;
;                  r1,r2,r3,r4 contains current position r5,r6 current encoderpos
;
;0 0 0 1 0 a a a   set POSITION origin current positions
;                  s1,s2,s3,s4 must contain new "current" positon, s5,s6 new encoderpos
;                              there are no flags to set.
;                  r1,r2,r3,r4 contains current position r5,r6 current encoderpos
;
;x x 1 x x a a a   stop directly, and receive positions.
;                  This cleares the STEP_ON flag, after receiving the first
;                  byte (commandbyte). So, - if INT_AS_FRQ is set, this first byte
;                  is the only one of the complete sequence, which can effect a step.
;                  After receiving the last byte, the targetposition is also
;                  set to the current position.
;                  With this you can stop stepping immediately, with returning
;                  the real current position.
;                  s1,s2,s3,s4,s5,s6 undefined, not effect
;                  r1,r2,r3,r4 contains current position r5,r6 current encoderpos
;
;
;------------------------------------------------------------
;The configurations have to be done, before any of the stepping works is used.
;The normally way is after start-up, to send a config1, then a config2.
;After this the stepping can be switched on by using STEP_ON
;Have a look, that config1 uses a little bit more time ( up to 200 cycles )
;as the others depending on a generally bitscanning of maxvalues.
;
;
;0 1 0 y y a a a   GENERAL CONFIG
;                  s1 - s6 depends on y y y ( bit 4,3 )
;                  r1 contains boards address, - r2,r3,r4,r5,r6 undefined.
;
;0 1 0 0 1 a a a   config 1
;                  s1,s2,s3,s4 have to contain 32bit value maxvalue ( maxcircle )
;                  reflecting a 1/32 fullstep value.
;                  s5,s6 have to contain 16bit value encodervalue ( max nr. like 4000 )
;
;                  currentpos will be tested after each step, if it is equal
;                  maxvalue. In this case currentpos is set to 0.
;                  If currentpos underflows 0, after going left, currentpos
;                  will be set automatically to maxvalue -1.
;
;                  The same will be doing with current encoderposition, and encodervalue.
;                  This provides in every case the possibility to handle
;                  the current position as a circle like 360 degrees.
;                  Be sure to handle also the setted targetposition in the right
;                  way.
;
;                  r1 contains boards address, - r2,r3,r4,r5,r6 undefined.
;
;0 1 0 1 0 a a a   config 2
;
;                  s1 have to contain highbyte for 16 bit timervalue.
;                     (If INT_AS_FRQ is used, this has no effect.)
;
;                  s2 have to contain lowbyte for 16 bit timervalue.
;
;                  s3    have to contain max. microstepvalue msmax
;                        (FS=32, HS=16, 1/4=8, 1/8=4, 1/16=2, 1/32=1)
;                  s4    have to contain min. microstepvalue msmin
;                        (FS=32, HS=16, 1/4=8, 1/8=4, 1/16=2, 1/32=1)
;
;                        Normally all steps are done with msmin,handling
;                        allways 1/32 fullstep * msmin, because all positions
;                        are handled in this size. If msmax a value wich is
;                        greater then msmin, internally an adapting of stepsize
;                        will be tried. This means if currentpos far away from
;                        targetpos mscur will tried to set to msmax, if next valid
;                        motorpositon this allowes. Also if current near target
;                        mscur will be tried to decrease to msmin.
;                        If this bother's you, set max to the same value as msmin.
;                        The default used value is allways msmin.
;
;                  s5 have to contain default value for steplp
;                     steplp can be used to adjust additionally the
;                     INT_AS_FRQ, or TIMER_AS_FRQ frequency.
;                     STEP_WORK funcs like this. If it is called, it
;                     first test for flag STEP_ON. If this is not set
;                     only encoder-work will be done.
;                     If set, it decrements a counter, if this overflows
;                     from 0 to 0xff, the step-work will be done, - if
;                     not overflow, STEP_WORK will only doing encodertest.
;                     A value of 0 means directly STEP_WORK.
;                     
;                  s6 sets the driver-flags, handling how the program/int works.
;                       
;                  s6.7 INT_AS_FRQ      ;if 1, spi_int calls STEP_WORK, instead timer.
;                                       ;if used spi-byte-per-int,
;                                       ;spi-int funcs as frequency in this case.
;                                       ;(for this, when using 3 driverboards, with the
;                                       ;same cs-line, a max of 7200 Hz is recommended.
;                                       ;in this 7200 Hz a complete sequence, plus
;                                       ;CMD_WORK, and STEP_WORK can be handled for up
;                                       ;3 boards using the same CS/CLOCK-line.
;                                       ;If you send the sequence byte-per-byte
;                                       ;you can use higher frequencies, but be carefull. 
;                                       ;You can also adjust this using steplp.
;                                       ;This bit clears bits s6.6, and bit s6.2
;
;                  s6.6 TIMER_AS_FRQ    ;If this is 1, and s6.7 is 0, a timer will be used
;                                       ;to call STEP_WORK, instead interrupt, in the way,
;                                       ;that progloop compares a running timer with a configured
;                                       ;timervalue.
;                                       ;Have a look, that for target-systems a highly stable
;                                       ;frequency is normally not necessary, - but anyway,
;                                       ;we provide it :-)
;                                       ;You can also divide this frq, using an additionally
;                                       ;steplp for STEP_WORK.
;                                       ;Have a look, that the spi-interrupt bother the
;                                       ;stability of frequency.
;
;                  s6.5 INT_HANDLES_CMD ;if 1, spi_int handles CMD_WORK, instead progloop
;
;                  s6.4 reserved, currently not used
;
;                  s6.3 reserved, currently not used
;
;                  s6.2 NO_CIRCLE       ;These flag shuts off, the handling of sections, instead
;                                       ;calculation the direction dependend if currentpos is smaller
;                                       ;then targetpos. Have a look, that over-/underflowhandling
;                                       ;is done in the same way as for a circle.
;                                       ;So if your motor is going along a flatline
;                                       ;let him not move under 0, or over maxvalue.
;
;                  s6.1 reserved, currently not used
;
;                  s6.0 reserved, currently not used
;
;                  ATTENTION: These bits will be get as it is, so use it if
;                  you really know what you do. The effects of this are
;                  active directly next call of CMD_WORK.
;
;                  Have a look, that INT_AS_FRQ, and cmd-bit 7 = 1, together
;                  makes normally no sense, because interrupt then first call
;                  complete STEP_WORK, before receiving the rest of complete
;                  sequence. If it used anyway together, master have to wait
;                  after sending first byte ( cmd ), for at least the whole
;                  number of max. used cycles by STEP_WORK, before sending
;                  the rest of sequence.
;                  Another way, is to set INT_AS_FRQ off, with setTarget,
;                  before using sequence-per-int with cmd.7=1.
;
;                  r1 contains boards address, - r2,r3,r4,r5,r6 undefined.
;

;--------------------------------------------------------------------------------
;1 x x x x a a a   ALL THE SAME, but handled as complete sequence in one interrupt
;                  means, not received byte per interrupt,
;                  instead sequence received per single interrupt
;--------------------------------------------------------------------------------






;ADDITIONAL NOTES:
;The Pin PORTC6 ( TXT ) is used as an digital output.
;Whenever current pos is equal to targetpos,  this output is set to low
;Whenever current pos is not equal to target, this output is set to high
;You can use this for whatever digital inputs you want. 
;
;
CMD_WORK
	MOVLW	0x00
	CPFSEQ	spi_cmd,AC
	RETURN  ;is 0, we do nothing
;spi_cmd contains a valid command

	BTFSC	spi_cmd,H'0006',AC
	BRA		cmdwork_config

	BTFSC	spi_cmd,H'0005',AC
	BRA		cmdwork_stopandclear

	BTFSC	spi_cmd,H'0004',AC
	BRA		cmdwork_setpos

	BTFSC	spi_cmd,H'0003',AC
	BRA		cmdwork_settarget
	BRA		cmdworkend

cmdwork_settarget
	MOVFF	spiibuf0,target3
	MOVFF	spiibuf1,target2
	MOVFF	spiibuf2,target1
	MOVFF	spiibuf3,target0
	MOVFF	spiibuf5,run_flags

	BTFSS	run_flags,DONT_IGNORES5,AC
	BRA		cmdworkstend
	BCF		run_flags,DONT_IGNORES5,AC
	BTFSS	run_flags,CONTENTS5,AC
	BRA		cmdstsettval
	MOVFF	spiibuf4,steplp
	BRA		cmdworkstend
cmdstsettval
	MOVFF	spiibuf4,timerlow
cmdworkstend
	
	BTFSS	run_flags,RESTART_FRQ,AC
	BRA		cmdworkend
	MOVFF	steplp,steplpctr
	BTFSS	drv_flags,TIMER_AS_FRQ,AC
	BRA		cmdworkend

	CALL	start_timer

	BRA		cmdworkend


cmdwork_setpos
	MOVFF	spiibuf0,curpos3
	MOVFF	spiibuf1,curpos2
	MOVFF	spiibuf2,curpos1
	MOVFF	spiibuf3,curpos0
	MOVFF	spiibuf4,encHigh
	MOVFF	spiibuf4,encLow
	BRA		cmdworkend

cmdwork_stopandclear
	MOVFF	curpos3,target3
	MOVFF	curpos2,target2
	MOVFF	curpos1,target1
	MOVFF	curpos0,target0
	BRA		cmdworkend

cmdwork_config

	BTFSC	spi_cmd,H'0005',AC
	BRA		cmdwork_stopandclear

	BTFSC	spi_cmd,H'0004',AC
	BRA		cmdwork_config2

	BTFSC	spi_cmd,H'0003',AC
	BRA		cmdwork_config1
	BRA		cmdworkend

cmdwork_config1
	MOVFF	spiibuf0,maxpos3
	MOVFF	spiibuf1,maxpos2
	MOVFF	spiibuf2,maxpos1
	MOVFF	spiibuf3,maxpos0
	MOVFF	spiibuf4,encMaxHigh
	MOVFF	spiibuf5,encMaxLow
	CALL	init_scanoffset
	BRA		cmdworkend

cmdwork_config2
	MOVFF	spiibuf0,timerhigh
	MOVFF	spiibuf1,timerlow
	MOVFF	spiibuf2,msmax
	MOVFF	spiibuf3,msmin
	MOVFF	spiibuf3,mscur
	MOVFF	spiibuf4,steplp
	MOVFF	spiibuf5,drv_flags
	BTFSS	drv_flags,H'0003',AC
	BRA		cmdworkend ; skip if EEPROM_CFG is set

	;here we are if EERPROM_CFG is set.
	;@@@@@? should we implement this ?

cmdworkend
	CLRF	spi_cmd,AC ;at end we have to delete it
	RETURN
;( cycles with call, and return )
;NOP       max base  8 cycles max
;settarget max base 41 cycles max 
;setpos    max base 28 cycles max
;reserved  max base 17 cycles
;config1   max base 30 cycles + ~ 100 init_scanoffset
;config2   max base 30 cycles max