#include "main.h"
#include "ad0x0_spi2.h"
#include "ad0x0_spi_ext.h"
#include "../admisc/ad0x0_timman.h"
#include "stm32f1xx_hal_spi.h"
#include <string.h>

/*не проебать
SPE: SPI enable
в ините врубаем это SPIX->CR2 |= (SPI_CR2_ERRIE); 
*/

#define SPIX                ((SPI_TypeDef *)SPI2_BASE)
//#undef AD0X0_SPI2_DBG
//#define	  AD0X0_SPI2_DBG

//ADQS == AD0x0 Queue Spi
#define ADQS_SPI_EV_DISABLE 	SPIX->CR2 &= ~(SPI_CR2_TXEIE|SPI_CR2_RXNEIE);
/*Хотелось бы выключить нахер пилу, которая идет в прерывание SPI
Для этого события нужно включать только для команд предачи и выключать при операциях с очередью*/
#define ADQS_SPI_EV_GETSTATE(LAST_STATE) LAST_STATE=SPIX->CR2 & (SPI_CR2_TXEIE|SPI_CR2_RXNEIE);
#define ADQS_SPI_EV_SETSTATE(LAST_STATE) __disable_irq(); SPIX->CR2 &= ~(SPI_CR2_TXEIE|SPI_CR2_RXNEIE); SPIX->CR2 |= (LAST_STATE); __enable_irq();

#define ADQS_SPI_EV_ENABLE 		SPIX->CR2 |= (SPI_CR2_TXEIE|SPI_CR2_RXNEIE);
#define ADQS_SPI_DISABLE SPIX->CR1&= ~SPI_CR1_SPE;
#define ADQS_SPI_ENABLE SPIX->CR1|= SPI_CR1_SPE;

SPI_HandleTypeDef *phspi2=NULL;

__weak void 		ad0x0_spi2_err_cb(void);
void    ad0x0_spi2_process(void);
void    ad0x0_spi2_err(void);
void    ad0x0_spi2_pop(void);
void 		ad0x0_spi2_init_desc(void);
	
struct ad0x0_spi_cmd_s ad0x0_spi2_fifo[AD0X0_SPI_FIFO_COUNT];
volatile struct ad0x0_spi_cmd_s *ad0x0_spi2_pcurhwi=0,*ad0x0_spi2_pcurswi=0;
ad0x0_spi_desc_s ad0x0_spi2_desc;
volatile uint32_t ad0x0_spi2_last_HAL_RES=0, ad0x0_spi2_DMAERR_count=0;
volatile uint32_t ad0x0_spi2_wait_cycles=0,ad0x0_spi2_wait_cycles_push=0;
GPIO_TypeDef *AD_SPI2_DC_GPIO_Port=NULL, *AD_SPI2_RES_GPIO_Port=NULL,*AD_SPI2_NSS_GPIO_Port=NULL;
uint16_t AD_SPI2_DC_Pin=0, AD_SPI2_RES_Pin=0, AD_SPI2_NSS_Pin=0;
#ifdef AD0X0_DAMN_DBG
//volatile int16_t c_enter_process=0,c_enter_ext=0;
#endif

uint32_t ad0x0_spi2_lhwitime(void){
	uint32_t t=(HAL_GetTick()<ad0x0_spi2_desc.last_hwi_process_tick)
		?((uint64_t)HAL_GetTick()+UINT32_MAX-ad0x0_spi2_desc.last_hwi_process_tick)
		:(HAL_GetTick()-ad0x0_spi2_desc.last_hwi_process_tick);
	return t;
}

void    ad0x0_spi2_push(ADQS_t _ctype,uint8_t _cbyte){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#ifdef AD0X0_SPI2_DBG
  ADDBG2_HIGH;
#endif
	uint32_t t=ad0x0_spi2_lhwitime();
	uint16_t ev_state;
	if(t>2){//ms
/*		if(ad0x0_spi2_pcurhwi->ctype==0x4B){
			ad0x0_spi2_pop();
			ad0x0_spi2_process();
		}*/
	}
//	while((I2CX->CR1 & I2C_CR1_STOP));//это единственный while, который НЕЗАМЕТНО срабатывает раз в час...
	if(ad0x0_spi2_pcurswi->ctype & ADQS_EMPTY){
		ADQS_SPI_EV_GETSTATE(ev_state);
		ADQS_SPI_EV_DISABLE;
		__disable_irq();
    ad0x0_spi2_pcurswi->ctype=_ctype;
    ad0x0_spi2_pcurswi->cbyte=_cbyte;
    ad0x0_spi2_pcurswi=ad0x0_spi2_pcurswi->pnext;
		__enable_irq();
		if((!(ad0x0_spi2_pcurhwi->ctype & ADQS_PROCESSED)) ){
			ad0x0_spi2_process();//
		}else ADQS_SPI_EV_SETSTATE(ev_state);
		//ADQS_SPI_EV_ENABLE;//решить!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    #ifdef AD0X0_SPI2_DBG  
    ADDBG2_LOW;
    #endif
    return;
  }

  //ad0x0_spi2_pcurswi указывает на незанятый
  if(!(ad0x0_spi2_pcurswi->ctype & ADQS_EMPTY)){//если наткнулся на невыкинутый эл-т == очередь забита
		uint32_t c=10000000;
    ADQS_SPI_EV_ENABLE;
    while(!(ad0x0_spi2_pcurswi->ctype & ADQS_EMPTY) && c--){
			//__WFI();
			__asm("nop");__asm("nop");__asm("nop");__asm("nop");
			ad0x0_spi2_wait_cycles_push++;
    }    
    if(!(ad0x0_spi2_pcurswi->ctype & ADQS_EMPTY)){
      ad0x0_spi2_err();
    }
	}
	ADQS_SPI_EV_GETSTATE(ev_state);
	ADQS_SPI_EV_DISABLE;
	__disable_irq();
  ad0x0_spi2_pcurswi->ctype=_ctype;
  ad0x0_spi2_pcurswi->cbyte=_cbyte;
	ad0x0_spi2_pcurswi=ad0x0_spi2_pcurswi->pnext;
	__enable_irq();
	if((!(ad0x0_spi2_pcurhwi->ctype & ADQS_PROCESSED)) ){
    ad0x0_spi2_process();
	}else ADQS_SPI_EV_SETSTATE(ev_state);
	//ADQS_SPI_EV_ENABLE;//решить!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  #ifdef AD0X0_SPI2_DBG
  ADDBG2_LOW;
  #endif
}

void    ad0x0_spi2_pop(){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  int was_masked=__disable_irq();
	if(!(ad0x0_spi2_pcurhwi->ctype & ADQS_PROCESSED)){
    //попытка выкинуть необработанный элемент
		if(!was_masked)__enable_irq();
    ad0x0_spi2_err();
  }	
  ad0x0_spi2_pcurhwi->ctype|=0x80;//метим как выкинутую
  ad0x0_spi2_pcurhwi=ad0x0_spi2_pcurhwi->pnext;
	if(!was_masked)__enable_irq();
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

uint8_t    ad0x0_spi2_get_ext_async(uint8_t *_p_out_handle,ad0x0_spi_ext_t **_p_out_desc){
	uint8_t r=0;
	uint32_t ne_hvataet_suka_cpp=10000000;
	r = ad0x0_spi_ext_get(_p_out_handle, _p_out_desc);
	while( (!r) && ne_hvataet_suka_cpp--){
		__enable_irq(); 
		ad0x0_spi2_wait_cycles++; 
		ADQS_SPI_EV_ENABLE; 
		r = ad0x0_spi_ext_get(_p_out_handle, _p_out_desc);
	}
	if(!r){
		ad0x0_spi2_err();//пересмотреть!!!!!!!!!!!!!!!!!! мож надо ждать
	}
	return 1;
}

uint8_t    ad0x0_spi2_get_ext_async2(uint8_t *_p_out_handle,void **_p_out_spi_ext_t){
	uint8_t r=0;
	uint32_t ne_hvataet_suka_cpp=10000000;
	r = ad0x0_spi_ext_get(_p_out_handle, (ad0x0_spi_ext_t**)_p_out_spi_ext_t);
	while( (!r) && ne_hvataet_suka_cpp--){
		__enable_irq(); 
		ad0x0_spi2_wait_cycles++; 
		ADQS_SPI_EV_ENABLE; 
		r = ad0x0_spi_ext_get(_p_out_handle, (ad0x0_spi_ext_t**)_p_out_spi_ext_t);
	}
	if(!r){
		ad0x0_spi2_err();//пересмотреть!!!!!!!!!!!!!!!!!! мож надо ждать
	}
	return 1;
}

uint8_t    ad0x0_spi2_get_ext_setbuf(uint8_t *_tx_pbuf,uint8_t *_rx_pbuf, uint8_t _count){
	//c_enter_ext++;
	uint8_t i;	
	ad0x0_spi_ext_t *pf;
	ad0x0_spi2_get_ext_async(&i,&pf);
//	if(pf->pSetTXRXBuf ||pf->_p_cb_func|| pf->calls_count)ad0x0_spi2_err();//УБРАТЬ
	pf->pbuf_tx=_tx_pbuf;
	pf->pbuf_rx=_rx_pbuf;
	pf->pbuf_count=_count;
	pf->spi=SPIX;
	pf->p_pre_SetTXRXBuf=EXT_SetTXRXBuf;//ну я хз, пока делаем так... ПЕРЕДЕЛАТЬ!!!!!!
	return i;
	//ad0x0_spi2_push(ADQS_USE_EXT,i);
	//c_enter_ext--;
}

void    ad0x0_spi2_push_txrx_dma_ext(uint8_t *_tx_pbuf,uint8_t *_rx_pbuf, uint8_t _count){
	//c_enter_ext++;
	ad0x0_spi2_push(ADQS_TXRX_PBUF_DMA_EXT,ad0x0_spi2_get_ext_setbuf(_tx_pbuf,_rx_pbuf,_count));
	//c_enter_ext--;
}

void    ad0x0_spi2_push_tx_pbuf_ext(uint8_t *_tx_pbuf,uint8_t *_rx_pbuf, uint8_t _count){
	//c_enter_ext++;
	ad0x0_spi2_push(ADQS_TX_PBUF_EXT,ad0x0_spi2_get_ext_setbuf(_tx_pbuf,_rx_pbuf,_count));
	//c_enter_ext--;
}

void    ad0x0_spi2_push_tx_pbuf_dma_ext(uint8_t *_tx_pbuf,uint8_t *_rx_pbuf, uint8_t _count){
	//c_enter_ext++;
	ad0x0_spi2_push(ADQS_TX_PBUF_DMA_EXT,ad0x0_spi2_get_ext_setbuf(_tx_pbuf,_rx_pbuf,_count));
	//c_enter_ext--;
}

void    ad0x0_spi2_push_ext_setfunc(uint8_t _sf_id,void (*_p_cb_func)(uint8_t _sf_id,ad0x0_spi_desc_s *pdspi,void *p_spi_ext_t)){
	//c_enter_ext++;
	uint8_t i;	
	ad0x0_spi_ext_t *pf;
	ad0x0_spi2_get_ext_async(&i,&pf);
	pf->sf_id=_sf_id;
	pf->_p_post_cb_func=_p_cb_func;//ну я хз, пока делаем так... ПЕРЕДЕЛАТЬ!!!!!!
	pf->spi=SPIX;
	ad0x0_spi2_push(ADQS_USE_EXT,i);
	//c_enter_ext--;
}

uint8_t ad0x0_spi2_next(void){		
		ad0x0_spi2_pop();
		if(!(ad0x0_spi2_pcurhwi->ctype & ADQS_EMPTY)){//(очередь не пустая)
			ad0x0_spi2_process();
		}
		return 1;
}

void    ad0x0_spi2_process(void){
//c_enter_process++;
	//тут мы шото меняем какие то флаги, а затем ждем прерывания для текущей команды
#ifdef AD0X0_SPI2_DBG
//  ADDBG2_HIGH;
#endif
  //если тип не впишится в свитч, то комнда либо отброшена, либо обработана ранее
  switch(ad0x0_spi2_pcurhwi->ctype){
    case ADQS_TX:
				__disable_irq();
        //I2CX->CR1 |= I2C_CR1_ACK;
				if(ad0x0_spi2_pcurhwi->cbyte==0x1b){
					__asm("nop");  
				}
        ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
        SPIX->DR = ad0x0_spi2_pcurhwi->cbyte;		
				__enable_irq();
				ADQS_SPI_EV_ENABLE;
    break;
		case ADQS_TX_PBUF:
				__disable_irq();
				#ifdef SPI2_NSS_GPIO_Port
				HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port,SPI2_NSS_Pin,GPIO_PIN_RESET);
				#endif
				ad0x0_spi2_desc.pbuf_counter_cur=ad0x0_spi2_desc.pbuf_counter;
				ad0x0_spi2_desc.tx_pbuf_cur=ad0x0_spi2_desc.tx_pbuf;
				ad0x0_spi2_desc.rx_pbuf_cur=0;
        //ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;
				SPIX->DR = *ad0x0_spi2_desc.tx_pbuf_cur++;
				ad0x0_spi2_desc.pbuf_counter_cur--;
        ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную                
				__enable_irq();
				ADQS_SPI_EV_ENABLE;
    break;		
		case ADQS_TX_PBUF_EXT:
				__disable_irq();
				if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_RESET);
				//ext - ф-я дма, в случае перезапуска не выполняется, т.к. буферы уже назначены
				if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_pre_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
				}
				ad0x0_spi2_desc.pbuf_counter_cur=ad0x0_spi2_desc.pbuf_counter;
				ad0x0_spi2_desc.tx_pbuf_cur=ad0x0_spi2_desc.tx_pbuf;
				ad0x0_spi2_desc.rx_pbuf_cur=0;
        //ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;
				SPIX->DR = *ad0x0_spi2_desc.tx_pbuf_cur++;
				ad0x0_spi2_desc.pbuf_counter_cur--;
        ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную                
				__enable_irq();
				ADQS_SPI_EV_ENABLE;
    break;
		case ADQS_TX_PBUF_DMA:
				__disable_irq();
		//ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;//все через EXT
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную                
				__enable_irq();		
				ADQS_SPI_EV_DISABLE;
				if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_RESET);
				if((!ad0x0_spi2_desc.pbuf_counter) || (!ad0x0_spi2_desc.tx_pbuf) )ad0x0_spi2_err();
		
				ad0x0_spi2_last_HAL_RES=HAL_SPI_Transmit_DMA(phspi2,(uint8_t*)ad0x0_spi2_desc.tx_pbuf,ad0x0_spi2_desc.pbuf_counter);
				//for (uint32_t i=0;i<1000000;i++)
				if(HAL_OK != ad0x0_spi2_last_HAL_RES){
					ad0x0_spi2_pcurhwi->ctype&=~ADQS_PROCESSED;//финт ушами, 					
					ad0x0_spi2_DMAERR_count++;
					ADQS_SPI_EV_ENABLE;
				}else break;
				if(HAL_OK != ad0x0_spi2_last_HAL_RES)ad0x0_spi2_err();
    break;
		case ADQS_TX_PBUF_DMA_EXT:
				__disable_irq();
		//ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;//все через EXT
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную                
				if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_pre_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
				}
				__enable_irq();		
				ADQS_SPI_EV_DISABLE;
				if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_RESET);
				if((!ad0x0_spi2_desc.pbuf_counter) || (!ad0x0_spi2_desc.tx_pbuf) )ad0x0_spi2_err();
		
				ad0x0_spi2_last_HAL_RES=HAL_SPI_Transmit_DMA(phspi2,(uint8_t*)ad0x0_spi2_desc.tx_pbuf,ad0x0_spi2_desc.pbuf_counter);
				//for (uint32_t i=0;i<1000000;i++)
				if(HAL_OK != ad0x0_spi2_last_HAL_RES){
					ad0x0_spi2_pcurhwi->ctype&=~ADQS_PROCESSED;//финт ушами, 					
					ad0x0_spi2_DMAERR_count++;
					ADQS_SPI_EV_ENABLE;
				}else break;
				if(HAL_OK != ad0x0_spi2_last_HAL_RES)ad0x0_spi2_err();
    break;				
    case ADQS_TXRX_PBUF_DMA:
				__disable_irq();
				//тут дуализм сраный. сейчас байт данных не должен ни за что отвечать
				if(ad0x0_spi2_pcurhwi->cbyte)ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;		
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				__enable_irq();		
				ADQS_SPI_EV_DISABLE;
				if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_RESET);
				if((!ad0x0_spi2_desc.pbuf_counter) || (!ad0x0_spi2_desc.tx_pbuf) || (!ad0x0_spi2_desc.rx_pbuf) )ad0x0_spi2_err();
				ad0x0_spi2_last_HAL_RES=HAL_SPI_TransmitReceive_DMA(phspi2,(uint8_t*)ad0x0_spi2_desc.tx_pbuf,(uint8_t*)ad0x0_spi2_desc.rx_pbuf,ad0x0_spi2_desc.pbuf_counter);
				//for (uint32_t i=0;i<1000000;i++)
				if(HAL_OK != ad0x0_spi2_last_HAL_RES){
					ad0x0_spi2_pcurhwi->ctype&=~ADQS_PROCESSED;//финт ушами, 
					ad0x0_spi2_DMAERR_count++;
					ADQS_SPI_EV_ENABLE;
					//NVIC_SetPendingIRQ(SPI2_IRQn);//ПЕРЕСМОТРЕТЬ
				}
				//if(ad0x0_spi2_DMAERR_count>100)ad0x0_spi2_err();//ПЕРЕСМОТРЕТЬ
    break;
		case ADQS_TXRX_PBUF_DMA_EXT:
				__disable_irq();
				//тут дуализм сраный. сейчас байт данных не должен ни за что отвечать
				if(ad0x0_spi2_pcurhwi->cbyte)ad0x0_spi2_desc.pbuf_counter=ad0x0_spi2_pcurhwi->cbyte;		
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				//ext - ф-я дма, в случае перезапуска не выполняется, т.к. буферы уже назначены
				if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_pre_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
				}
				__enable_irq();		
				ADQS_SPI_EV_DISABLE;
				if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_RESET);
				if((!ad0x0_spi2_desc.pbuf_counter) || (!ad0x0_spi2_desc.tx_pbuf) || (!ad0x0_spi2_desc.rx_pbuf) )ad0x0_spi2_err();
				ad0x0_spi2_last_HAL_RES=HAL_SPI_TransmitReceive_DMA(phspi2,(uint8_t*)ad0x0_spi2_desc.tx_pbuf,(uint8_t*)ad0x0_spi2_desc.rx_pbuf,ad0x0_spi2_desc.pbuf_counter);
				//for (uint32_t i=0;i<1000000;i++)
				if(HAL_OK != ad0x0_spi2_last_HAL_RES){
					ad0x0_spi2_pcurhwi->ctype&=~ADQS_PROCESSED;//финт ушами, 
					ad0x0_spi2_DMAERR_count++;
					ADQS_SPI_EV_ENABLE;
					//NVIC_SetPendingIRQ(SPI2_IRQn);//ПЕРЕСМОТРЕТЬ
				}
				//if(ad0x0_spi2_DMAERR_count>100)ad0x0_spi2_err();//ПЕРЕСМОТРЕТЬ
    break;				
				
		case ADQS_USE_EXT:
				__disable_irq();
			if(ad0x0_spi2_pcurhwi->ctype & ADQS_PROCESSED){__enable_irq();ad0x0_spi2_err();}
			else{
        ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				ADQS_SPI_EV_ENABLE;//иначе очередь может остановиться и не просраться
				// ad0x0_spi2_pcurhwi->cbyte
				__enable_irq();
				uint8_t cb=ad0x0_spi2_pcurhwi->cbyte;
				ad0x0_spi2_pcurhwi->cbyte|=0x80;				
				ad0x0_spi_ext_pre_process(&ad0x0_spi2_desc,cb);
				ad0x0_spi_ext_post_process(&ad0x0_spi2_desc,cb);
        ad0x0_spi2_next();//если здесь накидывается куча команд, то стэк это.. того...
				//v2
				/*ad0x0_spi2_pop();
				ADQS_SPI_EV_ENABLE;
				NVIC_SetPendingIRQ(SPI2_IRQn);*/
				//v3
				/*ad0x0_spi2_pop();
				if(!(ad0x0_spi2_pcurhwi->ctype & ADQS_EMPTY)){//(очередь не пустая)
					ad0x0_spi2_process();
				}*/
			}
				//__enable_irq();				
    break;
    case ADQS_DELAY_MS:				
        ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				ad0x0_timman_add(ad0x0_spi2_pcurhwi->cbyte,ad0x0_spi2_next);        
    break;    
		case ADQS_ST7735_SET_DC:			
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				//если состояние пина не изменится, то выкидываем команду из очереди
				while(SPIX->SR & SPI_SR_BSY);				
				if(ad0x0_spi2_pcurhwi->pnext->cbyte==0xC0){
					__asm("nop");
				}
				if(AD_SPI2_DC_GPIO_Port)HAL_GPIO_WritePin( AD_SPI2_DC_GPIO_Port,AD_SPI2_DC_Pin,ad0x0_spi2_pcurhwi->cbyte ? GPIO_PIN_SET : GPIO_PIN_RESET);
				ad0x0_spi2_next();				
		break;
		case ADQS_ST7735_SET_CS:
			if(ad0x0_spi2_pcurhwi->cbyte){
				SPIX->CR1|= SPI_CR1_SSI;
				SPIX->CR1&=~SPI_CR1_SSM;//0: Software slave management disabled
			}else{
				SPIX->CR1&= ~SPI_CR1_SSI;
				SPIX->CR1|=SPI_CR1_SSM;//1: Software slave management enabled
			}
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				ad0x0_spi2_next();
		break;
		case ADQS_ST7735_SET_RESET:
			if(AD_SPI2_RES_GPIO_Port)HAL_GPIO_WritePin( AD_SPI2_RES_GPIO_Port,AD_SPI2_RES_Pin,ad0x0_spi2_pcurhwi->cbyte ? GPIO_PIN_SET : GPIO_PIN_RESET);		
				//HAL_GPIO_WritePin( AD_RES_GPIO_Port,AD_RES_Pin,ad0x0_spi2_pcurhwi->cbyte ? GPIO_PIN_SET : GPIO_PIN_RESET);		
				ad0x0_spi2_pcurhwi->ctype|=ADQS_PROCESSED;//метим как обработанную
				ad0x0_spi2_next();
		break;
  default:
      ad0x0_spi2_err();
  }
//c_enter_process--;
#ifdef AD0X0_SPI2_DBG
//  ADDBG2_LOW;
#endif
}

void 		ad0x0_spi2_irq_err(void){
	//я бы это не обрабатывал, если бы не пидорский гироскоп, который не прислал нак при адресе...
	//метим команду как необработанную и пробуем по новой
	uint8_t ctypex=ad0x0_spi2_pcurhwi->ctype;
	uint32_t sr=0;
	sr=SPIX->SR;//
	ad0x0_spi2_err();
  switch(ctypex & 0x3f){
  case ADQS_TX_PBUF_DMA:
	if(sr & SPI_SR_OVR){
		/*When the SPI is used only to transmit data, it is possible to enable only the SPI Tx DMA 
channel. In this case, the OVR flag is set because the data received are not read*/
		__ASM("nop");
	}
	break;
	default:
		ad0x0_spi2_err();
	}		
}

void ad0x0_spi2_dma_err(void){
	//всякая херня случается, и... приводит как всегда к ad0x0_spi2_err();
	uint8_t ctypex=ad0x0_spi2_pcurhwi->ctype;
	ad0x0_spi2_err();
}

void ad0x0_spi2_dma(void){
	uint8_t ctypex=ad0x0_spi2_pcurhwi->ctype;
	switch(ctypex & 0x3f){
	case ADQS_TX_PBUF_DMA:
		if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_SET);
		ad0x0_spi2_next();
  break;
	case ADQS_TXRX_PBUF_DMA:		
		if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_SET);
		//ad0x0_spi2_next();
	//v2	почему так? потому что начинает сыпаться ф-я хал с дма-передачей
		ad0x0_spi2_pop();
		NVIC_SetPendingIRQ(SPI2_IRQn);
  break;
	case ADQS_TX_PBUF_DMA_EXT:
		if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_SET);
		if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_post_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
					ad0x0_spi2_pcurhwi->cbyte|=0x80;					
		}
		//ad0x0_spi2_next();
	//v2	почему так? потому что начинает сыпаться ф-я хал с дма-передачей
		ad0x0_spi2_pop();
		NVIC_SetPendingIRQ(SPI2_IRQn);
  break;	
	case ADQS_TXRX_PBUF_DMA_EXT:
		if(AD_SPI2_NSS_GPIO_Port)HAL_GPIO_WritePin(AD_SPI2_NSS_GPIO_Port,AD_SPI2_NSS_Pin,GPIO_PIN_SET);
		if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_post_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
					ad0x0_spi2_pcurhwi->cbyte|=0x80;					
		}
		ad0x0_spi2_pop();
		NVIC_SetPendingIRQ(SPI2_IRQn);
  break;
  default:
    //}else{
      ad0x0_spi2_err();
    }
}

void ad0x0_spi2_irq(void)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
ad0x0_spi2_desc.insint=1;
  ADS1_HIGH;
	/* для и2ц было так: когда генерится стоп, игнорим прерывания, для spi так не делаем
	if(I2CX->CR1 & I2C_CR1_STOP){
		#ifdef AD0X0_SPI2_DBG
        ADINT_LOW;
      #endif      
			ad0x0_spi2_insint=0;
      return;
	}*/
/**/
	uint32_t sr=SPIX->SR;//
	/*if(sr & SPI_SR_RXNE){
		uint8_t data=SPIX->DR;
		sr=SPIX->SR;
	}*/
	
	uint8_t ctypex=ad0x0_spi2_pcurhwi->ctype;
  if(!(ctypex & ADQS_PROCESSED)){//эл-т для которого не делался process
    if(!(ad0x0_spi2_pcurhwi->ctype & ADQS_EMPTY)){//(очередь не пустая)
      ad0x0_spi2_process();
      #ifdef AD0X0_SPI2_DBG
        ADINT_LOW;
      #endif      
			ad0x0_spi2_desc.insint=0;
      return;
    }else ADQS_SPI_EV_DISABLE;
  }
  
  if(ctypex & ADQS_EMPTY){//уже обработанный эл-т...== пустая очередь    
      #ifdef AD0X0_SPI2_DBG
      ADINT_LOW;
      #endif
			ADQS_SPI_EV_DISABLE;
			//ADQS_SPI_DISABLE;
			ad0x0_spi2_desc.insint=0;
      return;
  }

	
  switch(ctypex & 0x3f){
 
  case ADQS_TX:
      if(sr & SPI_SR_TXE){
				/*
				так не сработает, т.к. прерывание приходит пока байт передается,
				Зато работает с ДМА!!!
				#ifdef SPI2_NSS_GPIO_Port			
				HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port,SPI2_NSS_Pin,GPIO_PIN_SET);
				#endif*/
        ad0x0_spi2_pop();
				if(!(ad0x0_spi2_pcurhwi->ctype & ADQS_EMPTY)){//(очередь не пустая)
					ad0x0_spi2_process();
				}  
      }
			if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;
      }
			ADQS_SPI_EV_DISABLE;
   break;    
	case ADQS_TX_PBUF:
		if(sr & SPI_SR_TXE)
		{
      if(ad0x0_spi2_desc.pbuf_counter_cur){
				__disable_irq();
				SPIX->DR = *ad0x0_spi2_desc.tx_pbuf_cur++;
        ad0x0_spi2_desc.pbuf_counter_cur--;
        __enable_irq();				
			}else{
				ADQS_SPI_EV_DISABLE;
				ad0x0_spi2_next();				
      }				
    }
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;
    }
		//ADQS_SPI_EV_DISABLE;
  break;
	case ADQS_TX_PBUF_EXT:
		if(sr & SPI_SR_TXE)
		{
      if(ad0x0_spi2_desc.pbuf_counter_cur){
				__disable_irq();
				SPIX->DR = *ad0x0_spi2_desc.tx_pbuf_cur++;
        ad0x0_spi2_desc.pbuf_counter_cur--;
        __enable_irq();				
			}else{
				ADQS_SPI_EV_DISABLE;
				if(!(ad0x0_spi2_pcurhwi->cbyte & 0x80)){
					ad0x0_spi_ext_post_process(&ad0x0_spi2_desc,ad0x0_spi2_pcurhwi->cbyte);
					ad0x0_spi2_pcurhwi->cbyte|=0x80;					
				}
				ad0x0_spi2_next();				
      }				
    }
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;
    }
		//ADQS_SPI_EV_DISABLE;
  break;		
	case ADQS_TX_PBUF_DMA:
/*		if(SPIX->CR2 & SPI_CR2_TXEIE){
			__asm("nop");
		}*/
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;
    }
		ADQS_SPI_EV_DISABLE;
  break;
	case ADQS_TX_PBUF_DMA_EXT:
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;
    }
		ADQS_SPI_EV_DISABLE;
  break;		
	case ADQS_TXRX_PBUF_DMA:
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;//Clearing the RXNE bit is performed by reading the SPI_DR register.
    }
		ADQS_SPI_EV_DISABLE;
  break;
	case ADQS_TXRX_PBUF_DMA_EXT:
		if(sr & SPI_SR_RXNE){//ad0x0 09102020 проверить
        uint8_t d=SPIX->DR;//Clearing the RXNE bit is performed by reading the SPI_DR register.
    }
		ADQS_SPI_EV_DISABLE;
  break;
	case ADQS_DELAY_MS:
		ADQS_SPI_EV_DISABLE;
	break;
	case ADQS_ST7735_SET_DC:
		ADQS_SPI_EV_DISABLE;
	break;
	case ADQS_USE_EXT:
		ADQS_SPI_EV_DISABLE;
	break;
  default:
    //}else{
      ad0x0_spi2_err();
    }
  ad0x0_spi2_desc.insint=0;
  ADS1_LOW;
}

void    ad0x0_spi2_initq(void){
  ad0x0_spi2_pcurhwi=ad0x0_spi2_pcurswi=ad0x0_spi2_fifo;
  ad0x0_spi2_fifo[AD0X0_SPI_FIFO_COUNT-1].pnext=ad0x0_spi2_fifo;
  ad0x0_spi2_fifo[AD0X0_SPI_FIFO_COUNT-1].ctype=ADQS_EMPTY;
  for(uint16_t i=0;i<=AD0X0_SPI_FIFO_COUNT-2;i++){
    ad0x0_spi2_fifo[i].pnext=ad0x0_spi2_fifo+i+1;
    ad0x0_spi2_fifo[i].ctype=ADQS_EMPTY;
  }
//   HAL_SPI_R
}

void    ad0x0_spi2_err(void){
	ad0x0_err();
}

uint8_t ad0x0_spi2_is_queue_empty(void){	
	return ((ad0x0_spi2_pcurhwi->ctype & ADQS_EMPTY) && (ad0x0_spi2_pcurhwi->pnext->ctype & ADQS_EMPTY) && !(SPIX->SR & SPI_SR_BSY));
}

void 		ad0x0_spi2_wait(void){
	uint16_t ev_state;
	ADQS_SPI_EV_GETSTATE(ev_state);
	while(!ad0x0_spi2_is_queue_empty()){ADQS_SPI_EV_ENABLE;}//!!!!!!!!!!ubrat' etot pizdets
	ADQS_SPI_EV_SETSTATE(ev_state);
}

void ad0x0_spi2_init(SPI_HandleTypeDef *_phspi2,GPIO_TypeDef *_LCD_DC_GPIO_Port,uint16_t _LCD_DC_Pin,	GPIO_TypeDef *_LCD_RES_GPIO_Port,uint16_t _LCD_RES_Pin,
	GPIO_TypeDef *_NSS_GPIO_Port,uint16_t _NSS_Pin) {
	phspi2=_phspi2;
	AD_SPI2_DC_GPIO_Port=_LCD_DC_GPIO_Port;
	AD_SPI2_DC_Pin=_LCD_DC_Pin;
	AD_SPI2_RES_GPIO_Port=_LCD_RES_GPIO_Port;
	AD_SPI2_RES_Pin=_LCD_RES_Pin;
	AD_SPI2_NSS_GPIO_Port=_NSS_GPIO_Port;
	AD_SPI2_NSS_Pin=_NSS_Pin;
	SPIX->CR1|= SPI_CR1_SSM;//1: Software slave management enabled
	SPIX->CR1|= SPI_CR1_SSI;//The value of this bit is forced onto the NSS pin and the IO value of the NSS pin is ignored
	SPIX->CR2 |= (SPI_CR2_ERRIE);
	SPIX->CR1|=SPI_CR1_SPE;	
  ad0x0_spi2_initq();
	ad0x0_spi2_init_desc();
//pins configuing in cubemx...main.c  
}

void 		ad0x0_spi2_init_desc(void){
	memset(&ad0x0_spi2_desc,0,sizeof(ad0x0_spi2_desc));
	ad0x0_spi2_desc.spix=SPIX;
	ad0x0_spi2_desc.perrfunc=ad0x0_spi2_err;
}
