.include "m48def.inc"
.include "stdmacro.asm"
.include "math.asm"

.dseg

CurrentHead:	.byte 1		;текущая позиция головки (от 0 до 64)
MotorMode:		.byte 1		;состояние двигателя (10=крутит назад 01=крутит вперед 00=остановлен)
Note:			.byte 2		;номер проигрываемой ноты из таблицы
MovesLeft:		.byte 2		;сколько еще осталось сделать щелчков двигателем

.cseg
		rjmp Reset
		reti ;rjmp Int0				;External interrupt request 0
		reti ;rjmp Int1				;External interrupt request 1
		reti ;rjmp PCint0			;Pin change interrupt request 0
		reti ;rjmp PCint1			;Pin change interrupt request 1
		reti ;rjmp PCint2			;Pin change interrupt request 2
		reti ;rjmp WDT				;Watchdog time-out interrupt
		reti ;rjmp Timer2_compA		;Timer/Counter2 compare match A
		reti ;rjmp Timer2_compB		;Timer/Counter2 compare match B
		reti ;rjmp Timer2_ovf		;Timer/Counter2 overflow
		reti ;rjmp Timer1_capt		;Timer/Counter1 capture event
		rjmp Timer1_compA		;Timer/Counter1 compare match A
		reti ;rjmp Timer1_compB		;Timer/Counter1 compare match B
		reti ;rjmp Timer1_ovf		;Timer/Counter1 overflow
		reti ;rjmp Timer0_compA 	;Timer/Counter0 compare match A
		reti ;rjmp Tmer0_compB		;Timer/Counter0 compare match B
		reti ;rjmp Tmer0_ovf		;Timer/Counter0 overflow
		reti ;rjmp SPI_STC			;SPI serial transfer complete
		reti ;rjmp Usart_RX			;USART Rx complete
		reti ;rjmp Usart_UDRE		;USART, data register empty
		reti ;rjmp Usart_TX			;USART Tx complete
		reti ;rjmp ADC				;ADC conversion complete
		reti ;rjmp EE_ready			;EEPROM ready
		reti ;rjmp Analog_comp		;Analog comparator
		reti ;rjmp TWI				;2-wire serial interface
		reti ;rjmp SPM_ready		;Store program memory ready
Reset:
		stack
		outi CurrentHead, 0
		outi MotorMode, 0
		outi Note, 0
		outi Note+1, 0
		outi MovesLeft, 0
		outi MovesLeft+1, 0

		outi TCCR1B, 0b00000011	;CLK/64
		outi OCR1AH, 0
		outi OCR1AL, 1
		outi TCNT1H, 0			;таймер для генерации частоты	
		outi TCNT1L, 0			;считает в 1/15625 долях секунды (64 мкс)
		outi TIMSK1, 0b00000010	;OCIE1A

		outi DDRD, 0b00000111	;PD0=DIR PD1=STEP PD2=ENABLE
		outi PortD, 0

		ldi R17, 100
	MoveUpAgain:
			dec R17
			rcall MoveDelay
			rcall MoveUp
			cpi R17, 0
			brne MoveUpAgain

		sei

Inf:
		nop
		nop
		nop
		rjmp Inf

GetNote:
		ldi ZL, low(Sound*2)
		ldi ZH, high(Sound*2)
		lds R17, Note
		lds R16, Note+1
		lsl R16
		rol R17
		lsl R16
		rol R17
		add ZL, R16
		adc ZH, R17
		lds R17, Note
		lds R16, Note+1
		ldi R18, 1
		add R16, R18
		clr R18
		adc R17, R18
		sts Note, R17
		sts Note+1, R16
		

		lpm YL, Z+		;в Y частота
		lpm YH, Z+
		clr R17
		ldi R16, 2
		cp YL, R16
		cpc YH, R17
		brsh Normal
			ldi R16, 1
			clr R17
			cp YL, R16
			cpc YH, R17
			brne Zero
				outi MovesLeft, 0
				outi MovesLeft+1, 1
				rjmp ChooseDir
		Zero:
			outi OCR1AH, 0		;если частота=0 то это либо пауза либо стоп
			outi OCR1AL, 125
			outi PortD, 4		;а поэтому выключим светодиод
			lpm R18, Z+
			lpm R17, Z+
			clr R16
			cp R18, R16
			cpc R17, R16
			breq SoundEnd
				lsr R17			;если и время!=0 то пауза
				ror R18
				lsr R17
				ror R18
				lsr R17
				ror R18
				sts MovesLeft, R17
				sts MovesLeft+1, R18
				outi MotorMode, 0
				ret
		SoundEnd:
			outi TCCR1B, 0
			cli
			rjmp Inf
			ret

	Normal:
		ldi XH, high(15625)
		ldi XL, low(15625)
		divxbyy			;в X - пауза между щелчками двигателя
		sts OCR1AH, XH
		sts OCR1AL, XL

		lsr YH
		ror YL			;в YL - частота/2
		lpm XL, Z+
		lpm XH, Z+
		lsr XH
		ror XL
		lsr XH
		ror XL			;в XL - время/4
		mul YL, XL
		mov XH, R1
		mov XL, R0
		ldi YH, 0
		ldi YL, 125
		divxbyy			;теперь в X число щелчков
		sts MovesLeft, XH
		sts MovesLeft+1, XL

ChooseDir:
		outi PortD, 0	;включим светодиод
		lds R16, CurrentHead		;теперь надо определить в какую сторону ехать
		cpi R16, 40
		brlo Less
			ldi R17, 0
			ldi R18, 80
			sub R18, R16
			inc R18
			cp XL, R18
			cpc XH, R17
			brlo GoDown
				rjmp GoUp
	Less:
		ldi R17, 0
		mov R18, R16
		inc R18
		cp XL, R18
		cpc XH, R17
		brlo GoUp
			rjmp GoDown

	GoDown:
		incram CurrentHead
		outi MotorMode, 0b00000010
		ret
	GoUp:
		incram CurrentHead
		outi MotorMode, 0b00000001
		ret

Timer1_compA:
		outi TCNT1L, 0
		outi TCNT1H, 0
		lds R17, MovesLeft
		lds R18, MovesLeft+1
		clr R16
		cp R18, R16
		cpc R17, R16
		brne MakeTick
			rcall GetNote
			reti

	MakeTick:
		ldi R16, 1
		sub R18, R16
		sts MovesLeft+1, R18
		brcc NoCarry
			dec R17
	NoCarry:
		sts MovesLeft, R17
		sts MovesLeft+1, R18

	Tick:
		lds R16, MotorMode
		cpi R16, 0b00000010
		brne NotDown
			lds R16, CurrentHead
			cpi R16, 80
			brsh ChangeToUp
				rcall MoveDown
				rjmp EndTick
		ChangeToUp:
			outi MotorMode, 0b00000001
			rcall MoveUp
			rjmp EndTick

	NotDown:
		cpi R16, 0b00000001
		brne EndTick
			lds R16, CurrentHead
			cpi R16, 0
			breq ChangeToDown
				rcall MoveUp
				rjmp EndTick
		ChangeToDown:
			outi MotorMode, 0b00000010
			rcall MoveDown
			rjmp EndTick
	EndTick:
		reti

MoveUp:
		outi PortD, 0b00000001
		rcall MoveDelay
		outi PortD, 0b00000011
		rcall MoveDelay

		lds R16, CurrentHead
		cpi R16, 0
		brne EndMoveUp
			outi CurrentHead, 1
	EndMoveUp:
		decram CurrentHead
		outi PortD, 0b00000001
		ret

MoveDown:
		outi PortD, 0b00000000
		rcall MoveDelay
		outi PortD, 0b00000010
		rcall MoveDelay

		lds R16, CurrentHead
		cpi R16, 80
		brne EndMoveDown
			outi CurrentHead, 79
	EndMoveDown:
		incram CurrentHead
		outi PortD, 0b00000000
		ret

MoveDelay:
		ldi R16, 170
	LoopDelay:
			dec R16
			nop
			nop
			nop
			nop
			nop
			cpi R16, 0
			brne LoopDelay
		ret

Sound:	.dw 0,	750

		.include "Imperial_March.asm"
		;.include "Mortal_Kombat.asm"
		;.include "What_Is_Love.asm"
		;.include "Smoke_On_The_Water.asm"

		.dw 0, 0
