ymodem&sensor

/******************************************************************************
版权所有:  深圳普实科技有限公司  
文件名:    ymodem.h 
作者:      wangdy
创建日期:  2020/7/27
描述:      ymodem协议  
其它:      
修改历史:  //修改历史记录列表,每条修改记录应包含修改日期、修改者及修改内容简述
            序号    修改时间    修改人  修改内容
			????    ????/??/??  ??????  参考样式       
******************************************************************************/

/*********************************防止多次编译*********************************/
#ifndef _YMODEM_H_
#define _YMODEM_H_

/************************************头文件************************************/
#include <stdint.h>
#include <stdbool.h>
#include "flash_addr_def.h"

#define  IAP_MAX_DOWNLOAD_SIZE   IAP_APP_MAX_SIZE

/************************************宏定义************************************/

#define PACKET_SEQNO_INDEX      (1)
#define PACKET_SEQNO_COMP_INDEX (2)

#define PACKET_HEADER           (3)
#define PACKET_TRAILER          (2)
#define PACKET_OVERHEAD         (PACKET_HEADER + PACKET_TRAILER)
#define PACKET_SIZE             (128)
#define PACKET_1K_SIZE          (1024)

#define FILE_NAME_LENGTH        (256)
#define FILE_SIZE_LENGTH        (16)

#define SOH                     (0x01)  /* start of 128-byte data packet */
#define STX                     (0x02)  /* start of 1024-byte data packet */
#define EOT                     (0x04)  /* end of transmission */
#define ACK                     (0x06)  /* acknowledge */
#define NAK                     (0x15)  /* negative acknowledge */
#define CA                      (0x18)  /* two of these in succession aborts transfer */  //取消传输 
#define CRC16                   (0x43)  /* 'C' == 0x43, request 16-bit CRC */

#define ABORT1                  (0x41)  /* 'A' == 0x41, abort by user */
#define ABORT2                  (0x61)  /* 'a' == 0x61, abort by user */

#define NAK_TIMEOUT             (2000)
#define MAX_ERRORS              (5)

#define DOWN_FINISH_TIMEOUT  	3000	//下载完成后  多久重启 

/************************************枚举************************************/

typedef enum
{
	YMODEM_START = 0x01,
	YMODEM_DATATRANS,		//数据接收 
	YMODEM_END,
}_YMODEM_H_STATE;

/**********************************可导出变量**********************************/

//数据缓存  
typedef struct
{
	uint8_t 	packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];	//总长度  包含帧头和帧尾 
	uint16_t 	packed_len;										//长度信息  
	uint8_t     programe_packet_data[PACKET_1K_SIZE];			//当前包信息 
	uint16_t    programe_packet_data_len;						//当前包  有效数据 长度  
}_YMODEM_PACKET_INFO;

//接收数据超时处理 
typedef struct
{
	bool		Timeout_En_Flag;					//超时标记 
	uint32_t    Timeout_Count;						//超时计数 
	bool		Timeout_DownFinish_Flag;			//下载完了以后做超时标记 
	uint32_t	Timeout_DownFinish_Count;			//下载完了以后做超时记数 
}_YMODEM_TIMEOUT;

typedef struct
{
	_YMODEM_H_STATE     Ymodem_State;
	uint16_t			Ymodem_Current_Pack;		//当前传输包  为0包时,则是传输文件信息用的 
	bool				Ymodem_Pack_Analysis_Flag;	//协议解析标记 
}_YMODEM_VAR;


extern _YMODEM_VAR    Ymodem_Var;

//extern uint32_t FlashDestination;
//extern uint8_t file_name[FILE_NAME_LENGTH];

/***********************************函数实现***********************************/

void 	 Ymodem_Init(void);				//ymodem初始化 
static void Send_Byte(uint8_t c);		//单字节发送 
void 	 Ymodem_SendPacket(uint8_t *data, uint16_t length);		//发包数据 
void 	 Ymodem_Send_Error(void);
void 	 Ymodem_Recv_Byte(uint8_t byte);
void 	 Ymodem_Data_Analysis(void);
void 	 Ymodem_Start_Trans(void);		//ymodem准备传输数据  
void 	 IRQ_Ymode_Info(void);			//ymode超时信息 


#endif  /* _YMODEM_H_ */





























/******************************************************************************
版权所有:  深圳市普实科技有限公司 
文件名:    api_sensorcheck.c
作者:      wangdy
创建日期:  2020/06/29
描述:      传感器检测功能
其它:      
修改历史:  //修改历史记录列表,每条修改记录应包含修改日期、修改者及修改内容简述
            序号    修改时间    修改人  修改内容     
******************************************************************************/

/************************************头文件************************************/

#include "api_sensorcheck.h"
#include "printerConfig.h"
#include "bsp_sensor.h"
#include <string.h>
#include "yc_gpio.h"
#include "yc_timer.h"
#include "hard_config.h"
#include "bsp_sensor.h"
#include "hard_config.h"
#include "api_para_set.h"
#include "var_global.h"
#include "api_print.h"
/*************************************宏定义*************************************/

/*************************************变量*************************************/
volatile STRUCT_PAPER_LOCATION_INFO Paper_Location_Info;
KalmanInfo KFP_height={0,0,0,0,0,0};
//KalmanInfo KFP_height={0.02,0,0,0,0.001,0.543};
/*************************************函数*************************************/
/************************************************************************************************************
名称:    GapSensorSignal_Print
功能描述:获取间隙纸的值
输入参数:
输出参数:
返回值:
************************************************************************************************************/
//参数信息获取  循环执行
static PaperStateInfoTypeDef GapSensorSignal_Print(uint16_t ad_value,uint16_t have_paper_ref,uint16_t gap_ref) {
	//获取纸张位置 
	PaperStateInfoTypeDef  PaperState = {
		.HavePaper = SENSOR_NOPAPER,
		.Position = POSITION_UNKNOW
	};
	
	{
//		MyPrintf("ad_value_aaaaa= %d\r\n",ad_value);
		//检测有纸无纸 
		MyPrintf("have_paper_ref=%d\r\n",have_paper_ref); // have_paper_ref = 360
		if ((ad_value >= (have_paper_ref-10)) && (ad_value<1200))
		{
			PaperState.HavePaper = SENSOR_HAVEPAPER;    //1号机有纸是315-400;2号机有纸290-400
//			Print_Gap_CheckInfo.No_Paper_Flag = false ;
	//		MyPrintf("abcdefg---\r\n"); 
		}
		else {
			PaperState.HavePaper = SENSOR_NOPAPER;	
 
		}
		MyPrintf("gap_ref=%d\r\n",gap_ref);    // gap_ref = 500
		//检测当前纸的位置信息 
		if(SENSOR_HAVEPAPER == PaperState.HavePaper){
			MyPrintf("ad_value_aaaaa= %d\r\n",ad_value);
			if (ad_value >= (gap_ref-10))
			{
				PaperState.Position = POSITION_ON_PAPER;
		//		MyPrintf("POSITION_ON_PAPER\r\n");
			}
			else if(ad_value<(have_paper_ref+5))      																	//1号机间隙纸位值219-240;2号机间隙纸位值210-240
			{
				PaperState.Position = POSITION_ON_GAP;
				MyPrintf("POSITION_ON_GAP_11\n");
			}
		}
		else{
			PaperState.Position = POSITION_UNKNOW;
		}

		return PaperState;
	}

}
/************************************************************************************************************
名称:    BlackSensorSignal_Print
功能描述:获取黑标纸的值
输入参数:
输出参数:
返回值:
************************************************************************************************************/
//参数信息获取  循环执行
static PaperStateInfoTypeDef BlackSensorSignal_Print(uint16_t ad_value,uint16_t have_paper_ref,uint16_t gap_ref) {
	//获取纸张位置 
	PaperStateInfoTypeDef  PaperState = {
		.HavePaper = SENSOR_NOPAPER,
		.Position = POSITION_UNKNOW
	};
//   MyPrintf("black_paper_11111\r\n");
	//if(Store_Para.Print_Paper_Type_Para.PrintPaperType == PAPER_GAP)
	{
		//检测有纸无纸 
//		MyPrintf("have_paper_ref=%d\r\n",have_paper_ref); // have_paper_ref = 360
		//if (ad_value > have_paper_ref/*&&ad_value<1200*/)
		if (ad_value > 205)   //1号机没纸是204,2号机没纸时196
		{
			PaperState.HavePaper = SENSOR_HAVEPAPER;    //1号机有纸是315-400;2号机有纸290-400
		//	MyPrintf("abcdefg---\r\n"); 
		}
		else {
			PaperState.HavePaper = SENSOR_NOPAPER;	
		//	MyPrintf("1234567----\r\n"); 
		}
	//	MyPrintf("gap_ref=%d\r\n",gap_ref);    // gap_ref = 800
		//检测当前纸的位置信息 
		if(SENSOR_HAVEPAPER == PaperState.HavePaper){
//		MyPrintf("gap_ref= %d\r\n",gap_ref);	
			if (ad_value > 260&&ad_value<800){
				//if (ad_value > have_paper_ref&&ad_value<1200){
				PaperState.Position = POSITION_ON_PAPER;
			}
		//	else  if(ad_value >= gap_ref&&ad_value<=260) 
		//	else  if(ad_value >= 210&&ad_value<=260)        //1号机器参数
			else //if(ad_value >= 207&&ad_value<=230)      //1号机间隙纸位值219-240;2号机间隙纸位值210-240
			{
				PaperState.Position = POSITION_ON_GAP;
//				MyPrintf("abcdefg---2222\r\n"); 
			}
		}
		else{
			PaperState.Position = POSITION_UNKNOW;
		}

		return PaperState;
	}
}

//连续纸信息打印 
static PaperStateInfoTypeDef Continue_SensorSignal_Print(uint16_t ad_value,uint16_t have_paper_ref) {
	//获取纸张位置 
	PaperStateInfoTypeDef  PaperState = {
		.HavePaper = SENSOR_NOPAPER,
		.Position = POSITION_UNKNOW
	};
	
	if (ad_value > have_paper_ref){
		PaperState.HavePaper = SENSOR_HAVEPAPER;
	}
	else {
		PaperState.HavePaper = SENSOR_NOPAPER;	
	}
	
	return PaperState;
}

//打印时获取传感器位置信息   放在Task_PrintState_Process(void)函数中循环查询
PaperStateInfoTypeDef GetSensorPosition_Print(void)    //目前没用到
{
	PaperStateInfoTypeDef  PaperState = {0};
	uint16_t  ad_value;

	switch(Store_Para.Print_Paper_Type_Para.PrintPaperType)
	{
		case PAPER_GAP:{
			EnableSensor(PAPER_GAP,Store_CalibrationPara.SelectIndex);
	//		MyPrintf("SelectIndex=%02x\r\n",Store_CalibrationPara.SelectIndex);
			ad_value = StartSensorChannelADCValue();
		//	MyPrintf("ad_value=%d\r\n",ad_value);               //循环进来 ,不管有纸没纸,因为纸张类型默认设置为间隙纸   
			PaperState = GapSensorSignal_Print(ad_value,Store_CalibrationPara.HavePaperRef,Store_CalibrationPara.GapRef);	 
			break;
		}
		case PAPER_CONTINUE:{
			EnableSensor(PAPER_CONTINUE,Store_CalibrationPara.SelectIndex);
			ad_value = StartSensorChannelADCValue();
//			MyPrintf("GetSensorPosition_Print——22\r\n");
			PaperState = Continue_SensorSignal_Print(ad_value,Store_CalibrationPara.SelectIndex);
			break;
		}
		case PAPER_BLACKLABLE:
		{
			EnableSensor(PAPER_BLACKLABLE,Store_CalibrationPara.SelectIndex);
	//		MyPrintf("SelectIndex=%02x\r\n",Store_CalibrationPara.SelectIndex);
			ad_value = StartSensorChannelADCValue();
	//		MyPrintf("ad_value---=%d\r\n",ad_value);               //循环进来 ,不管有纸没纸,因为纸张类型默认设置为间隙纸   
			PaperState = BlackSensorSignal_Print(ad_value,Store_CalibrationPara.HavePaperRef,Store_CalibrationPara.BlackRef);
			break;
		}
		default:{
			break;
		}
	}
	
	PaperState.ADCValue = ad_value;		//ADC值 
	
	return PaperState;
}
void Init_KalmanInfo(KalmanInfo* info, double Q, double R)
{
	info->A = 1;  //标量卡尔曼
	info->H = 1;  //
	info->P = 10;  //后验状态估计值误差的方差的初始值(不要为0问题不大)
	info->Q = Q;    //预测(过程)噪声方差 影响收敛速率,可以根据实际需求给出
	info->R = R;    //测量(观测)噪声方差 可以通过实验手段获得
	info->filterValue = 0;// 测量的初始值
}
double KalmanFilter(KalmanInfo* kalmanInfo, double lastMeasurement)
{
	//预测下一时刻的值
	double predictValue = kalmanInfo->A* kalmanInfo->filterValue;   //x的先验估计由上一个时间点的后验估计值和输入信息给出,此处需要根据基站高度做一个修改
	
	//求协方差
	kalmanInfo->P = kalmanInfo->A*kalmanInfo->A*kalmanInfo->P + kalmanInfo->Q;  //计算先验均方差 p(n|n-1)=A^2*p(n-1|n-1)+q
	double preValue = kalmanInfo->filterValue;  //记录上次实际坐标的值
 
	//计算kalman增益
	kalmanInfo->kalmanGain = kalmanInfo->P*kalmanInfo->H / (kalmanInfo->P*kalmanInfo->H*kalmanInfo->H + kalmanInfo->R);  //Kg(k)= P(k|k-1) H’ / (H P(k|k-1) H’ + R)
	//修正结果,即计算滤波值
	kalmanInfo->filterValue = predictValue + (lastMeasurement - predictValue)*kalmanInfo->kalmanGain;  //利用残余的信息改善对x(t)的估计,给出后验估计,这个值也就是输出  X(k|k)= X(k|k-1)+Kg(k) (Z(k)-H X(k|k-1))
	//更新后验估计
	kalmanInfo->P = (1 - kalmanInfo->kalmanGain*kalmanInfo->H)*kalmanInfo->P;//计算后验均方差  P[n|n]=(1-K[n]*H)*P[n|n-1]
 
	return  kalmanInfo->filterValue;
}//
/*********************************************************************************************
判断检纸传感器的ADC是上升沿还是下降沿,还是paper hold

 这个算法是定义,paper_UP  ,PAPER_DOWN,PAPER_HOLD
**********************************************************************************************/
uint8_t PaperFilter(uint16_t *adc_buff,uint8_t filter_size)
{

	uint8_t i;
	uint8_t up_count = 0;
	uint8_t dn_count = 0;
	uint8_t up_count_ii = 0;
	uint8_t dn_count_ii = 0;

  static unsigned char counter=0;

//这个开始的时候不测试间隙。因为这个时候容易引入干扰
//10*4     5mm

	if(counter<10)
	{
    counter++;
		return PAPER_FILTER_HOLD;     
	}
//	MyPrintf("pf...\n");
	//check up
	if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType){
		for(i=0;i<(filter_size);i++){

		//	if((adc_buff[i]+bianhualiang)<adc_buff[i+1])	up_count++;
			if((adc_buff[i]+60)<adc_buff[i+1])	up_count++;
		//	if((adc_buff[i]-bianhualiang)>adc_buff[i+1])	dn_count++;
			if((adc_buff[i]-60)>adc_buff[i+1])	dn_count++;
			
			vTaskDelay(1);
		}
	}
	//黑标纸检测
	else if(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType){
		for(i=0;i<(filter_size);i++){

		//	if((adc_buff[i]+bianhualiang)<adc_buff[i+1])	up_count++;
			if((adc_buff[i]+90)<adc_buff[i+1])				up_count++;
			if((adc_buff[i]-100)>adc_buff[i+1])				dn_count++;
			vTaskDelay(1);
		}
	}
	

	if(up_count >= (filter_size-1))
	{
//		MyPrintf("paper up0 -- >%d\n",adc_buff[0]);
//		MyPrintf("paper up1 -- >%d\n",adc_buff[1]);
//		MyPrintf("paper up2 -- >%d\n",adc_buff[2]);
//		MyPrintf("paper up3 -- >%d\n",adc_buff[3]);
		//MyPrintf("paper up4 -- >%d\n",adc_buff[4]);
		return PAPER_FILTER_UP;   
	}
	else if(dn_count >=  (filter_size-1))
	{
//		MyPrintf("paper do0 -- >%d\n",adc_buff[0]);
//		MyPrintf("paper do1 -- >%d\n",adc_buff[1]);
//		MyPrintf("paper do2 -- >%d\n",adc_buff[2]);
//		MyPrintf("paper do3 -- >%d\n",adc_buff[3]);
	//	MyPrintf("paper do4 -- >%d\n",adc_buff[4]);
		return PAPER_FILTER_DOWM;
	}
	else
	{
		return PAPER_FILTER_HOLD;       

	}

}
//采集检纸传感器的ADC,并存入BUFF备用
void PushSensorAdc(uint8_t paper_type)
{
	uint8_t i;
	volatile uint16_t sum = 0,sum1=0;
	EnableSensor(PAPER_GAP,Store_CalibrationPara.SelectIndex);
	for(i=0;i<MAX_ADSW_CHANNEL;i++)      //MAX_ADSW_CHANNEL=4
	{ 
//		Paper_Location_Info.sensor_adc[i] =ADC_GetResult(ADC_CHANNEL_OC_PAPER_CHECK);
		Paper_Location_Info.sensor_adc[i] =	ADC_GetVoltage(ADC_CHANNEL_OC_PAPER_CHECK);
		sum += Paper_Location_Info.sensor_adc[i];
	}
	for(i=0;i<(MAX_FILTER_COUNT - 1);i++)
	{
		Paper_Location_Info.adc_filter[i] = Paper_Location_Info.adc_filter[i+1];
	}

    sum1=KalmanFilter(&KFP_height,(double)sum);//卡尔曼滤波
//	MyPrintf("sum1=%d \n",sum1);
	Paper_Location_Info.adc_filter[i] = sum1;
//  MyPrintf("i=%d \n",i);
	
#if 0
	for(i=0;i<MAX_ADSW_CHANNEL;i++)
	MyPrintf("%d ",PAPER.sensor_adc[i]);
	MyPrintf("%d ",sum);
	MyPrintf("%d ",sum1);
	MyPrintf("\n");	
#endif	
}

void GetPaperState(void)
{

	PushSensorAdc(Store_Para.Print_Paper_Type_Para.PrintPaperType);          //采集检纸传感器的ADC,并存入BUFF备用-

	Paper_Location_Info.last_gap_state = Paper_Location_Info.current_gap_state;

	Paper_Location_Info.current_gap_state = PaperFilter(&Paper_Location_Info.adc_filter[0],MAX_FILTER_COUNT);

	//MyPrintf("PAPER.current_gap_state=%d\n",PAPER.current_gap_state);
}




























/******************************************************************************
版权所有:  深圳普实科技有限公司  
文件名:    api_sensor_check.h   
作者:      wangdy  
创建日期:  2023/3/19
描述:      传感器检测 
其它:      
修改历史:  //修改历史记录列表,每条修改记录应包含修改日期、修改者及修改内容简述      
******************************************************************************/

/*********************************防止多次编译*********************************/
#ifndef _API_SENSOR_CHECK_H
#define _API_SENSOR_CHECK_H

/************************************头文件************************************/
#include <stdint.h>
#include <stdbool.h>
#include "bsp_sensor.h"
#include "printerConfig.h"
#include "driver_adc.h"

/************************************宏定义************************************/
#define PAPER_FILTER_HOLD		0        //保持
#define PAPER_FILTER_UP			1       //上升沿
#define PAPER_FILTER_DOWM		2       //下降沿

#define MAX_ADSW_CHANNEL		4
#define MAX_FILTER_COUNT		5       //过滤次数
#define bianhualiang	        (6)    //(12)     //变化量
/************************************枚举************************************/

//传感器 位置信息 
typedef enum {
	POSITION_UNKNOW	= 0,						//未知 
	POSITION_ON_PAPER,							//当前位置是有纸的状态  
	POSITION_ON_GAP,							//当前位置是间隙的状态  
}SensorPaperPositionEnum;

//传感器 信息 
typedef enum {
	SENSOR_HAVEPAPER,							//有纸状态  
	SENSOR_NOPAPER,								//无纸状态  
}SensorHaveParaStateEnum;

/************************************结构体************************************/


//位置信息 (纸张及其位置信息)
typedef struct
{
	SensorHaveParaStateEnum		HavePaper;	//是否有纸 
	SensorPaperPositionEnum		Position;	//纸张位置  
	uint16_t					ADCValue;	//电压值 
}PaperStateInfoTypeDef;

typedef  struct
{
	double filterValue;  //k-1时刻的滤波值,即是k-1时刻的值
	double kalmanGain;   //   Kalamn增益
	double A;   // x(n)=A*x(n-1)+u(n),u(n)~N(0,Q)
	double H;   // z(n)=H*x(n)+w(n),w(n)~N(0,R)
	double Q;   //预测过程噪声偏差的方差
	double R;   //测量噪声偏差,(系统搭建好以后,通过测量统计实验获得)
	double P;   //估计误差协方差
}KalmanInfo;

//纸张位置信息2
typedef struct  StructPaper{

	uint8_t move_ctl_state;          //电机步进控制的类型
	uint8_t last_gap_state;
	uint8_t current_gap_state;       //当前缺口状态
	uint8_t type;
	uint8_t auto_cal_type;

	uint8_t print_density;   //[0,14]
	uint8_t print_speed;     //[0,4]
	uint16_t print_speed_time_multiple;
	uint8_t move_to_cut_flag;
	uint8_t calibrate_state;        //校准状态
	uint8_t auto_calibrate_flag;     //定标开始及结束标志
	uint8_t calibrate_error_flag;    //校验错误标志
	uint16_t sensor_adc[MAX_ADSW_CHANNEL];
	uint16_t adc_filter[MAX_FILTER_COUNT];         //adc过滤
	uint16_t adj_gap_size;
	uint16_t adj_bm_size;
	uint16_t adj_hold_size;
	uint16_t adj_paper_size;

	uint16_t paper_end_flag;
	uint16_t paper_start_offset_flag;
	uint16_t paper_start_offset;	

	uint16_t size_h;	              //纸张高度
	uint16_t print_size;            //打印内容长度
	uint16_t offest_fh;              //打印内容纵向偏移量
	uint8_t printing_process_flag;   //打印开始及结束标志
	uint8_t NAK_flag;                //空走纸标志
	unsigned int  PaperAdc;          //存放纸的ADC值
}STRUCT_PAPER_LOCATION_INFO;

/**********************************可导出变量**********************************/
extern volatile STRUCT_PAPER_LOCATION_INFO Paper_Location_Info;

/***********************************函数实现***********************************/
extern int  GetSensorPosition(PrintPaperTypeEnum SensorType);
extern PaperStateInfoTypeDef GetSensorPosition_Print(void);
extern KalmanInfo KFP_height;
extern double KalmanFilter(KalmanInfo* kalmanInfo, double lastMeasurement);
extern void Init_KalmanInfo(KalmanInfo* info, double Q, double R);
extern void GetPaperState(void);
#endif































/******************************************************************************
版权所有:  深圳市普实科技有限公司 
文件名:    api_paper_calibration.c
作者:      wangdy
创建日期:  2020/06/29
描述:      蓝牙模块初始化 
其它:      
修改历史:  //修改历史记录列表,每条修改记录应包含修改日期、修改者及修改内容简述
            序号    修改时间    修改人  修改内容
			????    ????/??/??  ??????  参考样式       
******************************************************************************/

/************************************头文件************************************/

#include "printerConfig.h"
#include "bsp_w25x.h"
#include <string.h>
#include "yc_gpio.h"
#include "yc_timer.h"
#include "hard_config.h"
#include "bsp_sensor.h"
#include "api_sensorcheck.h"
#include "api_state_check.h"
#include "api_para_set.h"
#include "driver_adc.h"
#include "bsp_motor_control.h"
#include "printerConfig.h"
#include "var_global.h"
#include "driver_iwdg.h"
#include "api_paper_calibration.h"
#include "api_led_watchdog.h"
#include "api_key.h"
#include "bsp_print_control.h"
#include "var_print_selftest_font.h"
#include "tools_function.h"
#include "tools_calc_heattime.h"
#include "api_power_control.h"
#include "api_print.h"
#include "driver_spi.h"
#include "version.h"
#include "types.h"
#include <stdio.h>
#include <stdlib.h>
#include "api_supplies.h"
/*************************************宏定义*************************************/


/*************************************变量*************************************/

CaliValue_Table_TypeDef   CaliValue_Table = { 0 };

const uint16_t Cali_NoPaper_ADC[MAX_SENSOR_SCALE] = {
	1200,
	1200,
	1200,
	1200,
	650,
	200,
	280,
	160
};

/*************************************函数*************************************/

//表数据初始化 
static void CaliValueTable_Deinit(){
	int i = 0;
	int j = 0;
//	for(i = CALI_MAX_SCALE - CALI_MIN_SCALE; i>= 0; i--){
	for(i = CALI_MAX_SCALE - CALI_MIN_SCALE; i>= 2; i--){
		for(int j = 0; j<CALI_VALUE_TABLE_SIZE; j++){
			if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType){
			//初始化值  最大最小反填充   
				CaliValue_Table.ValueTable[i].Min_ValueTable[j] = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Max_ValueTable[j] = CALI_ADC_MIN_VALUE;       //最小表值原来是0,重调传感器电阻之后最小值在200左右
				CaliValue_Table.ValueTable[i].ValueTableValidFlag = false;			//有效标记清除 
				CaliValue_Table.ValueTable[i].Min_Ave = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Max_Ave = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Min_Current_Index = 0;
				CaliValue_Table.ValueTable[i].Max_Current_Index = 0;
				CaliValue_Table.ValueTable[i].PaperGapMinContinueCount = 0;
			}else if(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType){
				CaliValue_Table.ValueTable[i].Min_ValueTable[j] = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Max_ValueTable[j] = CALI_ADC_MIN_VALUE;       //最小表值原来是0,重调传感器电阻之后最小值在200左右
				CaliValue_Table.ValueTable[i].ValueTableValidFlag = false;			//有效标记清除 
				CaliValue_Table.ValueTable[i].Min_Ave = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Max_Ave = CALI_ADC_MAX_VALUE;
				CaliValue_Table.ValueTable[i].Min_Current_Index = 0;
				CaliValue_Table.ValueTable[i].Max_Current_Index = 0;
				CaliValue_Table.ValueTable[i].PaperGapMinContinueCount = 0;
			}
		}
	}
}

//打印自检初始化
static void CaliSelftPrintTestInit(){
	PrintTestBufTypeDef  TestBuf = {0};
	
	memset((char *)&TestBuf,0x00,sizeof(PrintTestBufTypeDef));
	
	//初始化信息 
//	sprintf((char *)TestBuf.First_Line,"NAME: %s",(char *)&GlobleMachineVar.DefaultGenMachineName[0]);	//BT NAME 	Store_Para.BT_Name_Para.Bt_Name
	sprintf((char *)TestBuf.First_Line,"NAME: %s",Store_Para.BT_Name_Para.Bt_Name);	//BT NAME
	sprintf((char *)TestBuf.Second_Line,"MAC: %02X.%02X.%02X.%02X.%02X.%02X",BtRxTxVar.BtMacAddr[0],BtRxTxVar.BtMacAddr[1],		//MAC 
																		BtRxTxVar.BtMacAddr[2],BtRxTxVar.BtMacAddr[3],
																		BtRxTxVar.BtMacAddr[4],BtRxTxVar.BtMacAddr[5]);
	sprintf((char *)TestBuf.Third_Line,"POR: %d%%",adc_channel_average_value.Power_Bat_Percent);	//电池电量百分比 
	sprintf((char *)TestBuf.Fourth_Line,"VER: V%s",VERSION);		//版本号 
	
	//复位打印自检信息 
	ResetPrintSelfTestData(TestBuf);
}
//更新表数据  
static void CaliValueTable_Update(int index,uint16_t value){
	uint32_t all_value_min = 0,all_value_max = 0;
	if(index > (CALI_MAX_SCALE - CALI_MIN_SCALE)){
		return;
	}
	
	//求最大表格  和最小表格的平均值 
	//最小  
	for(int j = 0; j< CALI_VALUE_TABLE_SIZE; j++){
		all_value_min += CaliValue_Table.ValueTable[index].Min_ValueTable[j];
	}
	CaliValue_Table.ValueTable[index].Min_Ave = all_value_min / CALI_VALUE_TABLE_SIZE;
	if(index == 1)
	 MyPrintf("Min_Ave=%d\r\n",CaliValue_Table.ValueTable[index].Min_Ave);
	//最大 
	for(int j = 0; j< CALI_VALUE_TABLE_SIZE; j++){
		all_value_max += CaliValue_Table.ValueTable[index].Max_ValueTable[j];
	}	
	CaliValue_Table.ValueTable[index].Max_Ave = all_value_max / CALI_VALUE_TABLE_SIZE;
	if(index == 1)
	MyPrintf("Max_Ave=%d\r\n",CaliValue_Table.ValueTable[index].Max_Ave);
	
	//将值加到数组里去(大于最大平均 或者小于最小平均 则替换数据)
	if(value < CaliValue_Table.ValueTable[index].Min_Ave){
		CaliValue_Table.ValueTable[index].Min_ValueTable[CaliValue_Table.ValueTable[index].Min_Current_Index++] = value;
		CaliValue_Table.ValueTable[index].Min_Current_Index %= CALI_VALUE_TABLE_SIZE;
		CaliValue_Table.ValueTable[index].Min_Min = value;		//最小值 
	}
	if(value > CaliValue_Table.ValueTable[index].Max_Ave){
		CaliValue_Table.ValueTable[index].Max_ValueTable[CaliValue_Table.ValueTable[index].Max_Current_Index++] = value;
		CaliValue_Table.ValueTable[index].Max_Current_Index %= CALI_VALUE_TABLE_SIZE;
	}
}

/******************************************************************************************************************************
定标:间隙纸

******************************************************************************************************************************/
//双击校准  --- 间隙纸   
static CaliResult_TypeDef PaperCali_GapPaper(void)
{
	CaliResult_TypeDef		result;						//间隙纸定标结果  
	static uint8_t  MotorBackCurrCnt = 0;
	static uint32_t MotorCurrCnt = 0;
	int scale_index = 0;								//临时变量 
	bool  Find_Success_Flag = false;					//找到结果了 
	
	uint32_t   Limit_Distance = CALIBRATE_FEEDLIMIT;	//最长多长 还找不到 就认为定标失败了   这里默认100mm
	uint8_t   PRintHead_Inverse_Pix = 56;     //回退距离
	uint16_t  ADC_Value = 0 ;
	uint16_t  ADC_Last_Value = 0 ;
	uint16_t  Res = 0 ;
	SelfTestLineTypeDef  PrintSeltTestData = {0};	//一行测试数据  
	//初始化变量值 
	CaliValueTable_Deinit();				
	
	//开启电机及打印头电源 
SPI_PrintHead_Configure();		//打印头初始化 
	Matchine_5V_PrintHead_Motor_Power_On();
	Print_Line_Stop_Write_Heat();
	delay_ms(100);
	MyPrintf("PaperCali_GapPaper--\r\n");
	//走回退部分
	while((PRintHead_Inverse_Pix>0)){
		IWDG_Feed;
		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_INVERSE,true);	//电机反转 走一步 
		delay_us(500);
		MotorBackCurrCnt++ ;
		if(MotorBackCurrCnt < PIX_MOTOR_N_STEP){
			continue;
		}
		MotorBackCurrCnt = 0;
		PRintHead_Inverse_Pix--;
	//	
	}
	PrintMotor_Stop();
	//循环查找  寻找定标位置及信息 
	while ((Limit_Distance > 0) ){
		//喂狗 
		IWDG_Feed;	
		//灯和按键  继续有效 
			
		//电机转动 2步走1个像素大小 
		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,true);	//电机正转 走一步   
		delay_us(500);
			
		//变量++
		MotorCurrCnt++;
		if(MotorCurrCnt < PIX_MOTOR_N_STEP){
			continue;
		}
		
		
		MotorCurrCnt = 0;
		Limit_Distance--;
		if(Limit_Distance>= (CALIBRATE_FEEDLIMIT-16)){
			continue;
		}
		if(Limit_Distance<= (CALIBRATE_FEEDLIMIT-64)){
			SuppliesDecLength++;
		}
		//打印一行数据  
		if(getPrintSelfTestData(&PrintSeltTestData)){
			//计算当前打印点数 	
			uint16_t PrintPoint = CalcPrintDataBitCount(PrintSeltTestData.LineData,PRINTER_LINE_BYTES);
			//计算加热时间 
			Print_Data_Cache.PrintHeatTime = Calc_Heattime(
															3800,            //adc_channel_average_value.Power_Bat_Value,  //自检打印写为固定的值
															PrintPoint,
															38                   //Print_Data_Cache.PrintDensity 	  //浓度  Find_Success_Flag = false;
														  );
			
			//如果读成功了  表明里面有数据的  则准备打印 
//_			Print_Line_Start_Write_Heat_WithOffset(PrintSeltTestData.LineData,false,Store_Para.Pix_Offset_Para.Pix_Offset);
			Print_Line_Start_Write_Heat_WithOffset(PrintSeltTestData.LineData,false,0);
			//开始加热  
			TIMER_HEATTIME_START;
		}
//		MyPrintf("PrintPaperType=%d\n\r",Store_Para.Print_Paper_Type_Para.PrintPaperType);
		GetPaperState();
		EnableSensor(PAPER_GAP,Store_CalibrationPara.SelectIndex);
		if((PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType)||(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType))
		{	  	
			//判断其是否持续一段时间的间隙
					
//					MyPrintf("current_gap_state=%d\n\r",Paper_Location_Info.current_gap_state);
			    ADC_Last_Value = Res ;
				ADC_Value = ADC_GetVoltage(ADC_CHANNEL_OC_PAPER_CHECK);
			    Res = MAX(ADC_Last_Value,ADC_Value);
				if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType){	
					if(Paper_Location_Info.current_gap_state == PAPER_FILTER_DOWM && Paper_Location_Info.last_gap_state != PAPER_FILTER_HOLD)
					{
						Limit_Distance = 0;
						Find_Success_Flag = true;		//找到突变位置成功了 
						MyPrintf("gap_true_paper_gap--\n");
																						
					}			
				}
				else if(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType){
				//	MyPrintf("POSITION_ON_black_11\n");
					if(Paper_Location_Info.current_gap_state == PAPER_FILTER_UP && Paper_Location_Info.last_gap_state != PAPER_FILTER_HOLD)
					{
						//MyPrintf("POSITION_ON_black_22\n");
						Limit_Distance = 0;
						Find_Success_Flag = true;		//找到突变位置成功了 
						MyPrintf("black_gap_true\n");									
					}			
				
				}
				
		}
															
	}
	
	if(true == Find_Success_Flag) {
	
		//走到撕纸处 
//		Limit_Distance = PRINTHEAD_OPTICALCOUPLER_CALIBRATION_CUTTER;
		if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType)
		   Limit_Distance = 196;
		else if(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType)   
		   Limit_Distance = 196;
		while ((Limit_Distance > 0) ){
			//喂狗 
			IWDG_Feed;				
			//电机转动 2步走1个像素大小 
			PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,true);	//电机正转 走一步 

			delay_us(500);
			
            for(uint16_t II =0;II<=12;II++){MyPrintf("44444444444\r\n");}		
			//变量++
			MotorCurrCnt++;
			if(MotorCurrCnt < PIX_MOTOR_N_STEP){
				continue;
			}
			MotorCurrCnt = 0;
			SuppliesDecLength++;
			//打印一行数据  
			if(getPrintSelfTestData(&PrintSeltTestData)){
				//计算当前打印点数 	
				uint16_t PrintPoint = CalcPrintDataBitCount(PrintSeltTestData.LineData,PRINTER_LINE_BYTES);
				//计算加热时间 
				Print_Data_Cache.PrintHeatTime = Calc_Heattime(
																3800,             //adc_channel_average_value.Power_Bat_Value,
																PrintPoint,
																38                //Print_Data_Cache.PrintDensity 	  //浓度 
															  );
				
				//如果读成功了  表明里面有数据的  则准备打印 
				Print_Line_Start_Write_Heat_WithOffset(PrintSeltTestData.LineData,false,0);
				//开始加热  
				TIMER_HEATTIME_START;
			}
			
			Limit_Distance--;	
		}
		
		//关闭电机使能 
		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,false);
		Print_Process_Para.Paper_Back_Flag = PRINT_STILL_PAPER;	//转为电机不动状态 
		//关闭电机及打印头电源 
		Matchine_5V_PrintHead_Motor_Power_Off();
//		if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType)
		{
		//更新值信息 
			result.isValidFlag = true;
			result.Gap_RefValue = GAP_THRESHOLD_DEFAULT;
			result.SelectedIndex = SELECTED_INDEX_DEFAULT;	
			result.HavePaper_RefValue = Res;      //有纸间隙处的值
			result.Black_RefValue = BLACK_THRESHOLD_DEFAULT; 
		}
		Find_Success_Flag = false;
	}else {
		//关闭电机使能 
		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,false);
		Print_Process_Para.Paper_Back_Flag = PRINT_STILL_PAPER;	//转为电机不动状态
		//关闭电机及打印头电源 
		Matchine_5V_PrintHead_Motor_Power_Off();
		
		//默认值  
		result.isValidFlag = false;
		result.Gap_RefValue = GAP_THRESHOLD_DEFAULT;
		result.SelectedIndex = SELECTED_INDEX_DEFAULT;	
		result.HavePaper_RefValue = NOPAPER_THRESHOLD_DEFAULT;      //
		result.Black_RefValue = BLACK_THRESHOLD_DEFAULT; 
		Print_Gap_CheckInfo.PaperGap_Gap_NoCheck_ErrorFlag = true;
		Find_Success_Flag = false;
//		MyPrintf("44444444444\r\n");
	}
	
	return result;
}

/******************************************************************************************************************************
定标:连续纸

******************************************************************************************************************************/
//校准 --- 连续纸  
static CaliResult_TypeDef PaperCali_ContinuePaper(void)
{
	CaliResult_TypeDef		result;						//间隙纸定标结果  
	static uint32_t MotorCurrCnt = 0;
	uint32_t   Limit_Distance = 0;	//最长多长 还找不到 就认为定标失败了 			
	
	//开启电机及打印头电源 
	Matchine_5V_PrintHead_Motor_Power_On();
	delay_ms(100);
		
	//走到撕纸处 
	Limit_Distance = CALIBRATE_CONTINUE_PAPER_FEEDLIMIT;	
	while ((Limit_Distance > 0) ){
		//喂狗 
		IWDG_Feed;	
		//灯和按键  继续有效 
		LED_Update();
		
		//电机转动 2步走1个像素大小 
		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,true);	//电机正转 走一步 
//		PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_INVERSE,true);
		delay_us(500);
			
		//变量++
		MotorCurrCnt++;
		if(MotorCurrCnt < PIX_MOTOR_N_STEP){
			continue;
		}
		MotorCurrCnt = 0;
		Limit_Distance--;	
	}
	
	//关闭电机使能 
	PrintMotor_CalibrationRunOnPhase(MOTOR_RUN_POSITIVE,false);
	//关闭电机及打印头电源 
	Matchine_5V_PrintHead_Motor_Power_Off();
	
	//默认值  
	result.isValidFlag = false;
	result.Gap_RefValue = GAP_THRESHOLD_DEFAULT;
	result.SelectedIndex = SELECTED_INDEX_DEFAULT;	
	result.HavePaper_RefValue = NOPAPER_THRESHOLD_DEFAULT;
	
	return result;
}

//校准进程   双击按键校准
void PaperCali_Process(void) {
	Print_Gap_CheckInfo.PaperGap_Gap_NoCheck_ErrorFlag = false;		//未定标前 默认为成功 
	CaliResult_TypeDef Calresult = {0};
	static CalibrationParaStoreTypeDef calipara = {0};
	Var_Power_Control.Auto_Power_Off_Reclock_Flag = true;      //有定标就重新计算关机时间
	//初始化打印自检变量 
	CaliSelftPrintTestInit();
	//清除掉现有所有缓存  
	FIFO_PrintLineList_Clear();		//打印数据清除  
	FIFO_DataAnalysis_Clear();		//解析数据清除 
	//开始进入标定进程  
	if((PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType)||(PAPER_BLACKLABLE == Store_Para.Print_Paper_Type_Para.PrintPaperType)){
		Calresult = PaperCali_GapPaper();
	}else if(PAPER_CONTINUE == Store_Para.Print_Paper_Type_Para.PrintPaperType){
		Calresult = PaperCali_ContinuePaper();
	}
//	MyPrintf("PaperCali_Process\r\n"); 
	//存储进flash  定标完成了 开始存flash 
	//定标参数存储 

	calipara.SelectIndex = Calresult.SelectedIndex;
	calipara.GapRef = Calresult.Gap_RefValue;
	calipara.HavePaperRef = Calresult.HavePaper_RefValue;
	calipara.BlackRef = Calresult.Black_RefValue; //
	calipara.isSuccess = Calresult.isValidFlag;
	calipara.storeFlag = 0;
//	MyPrintf("HavePaperRef=%d\r\n",calipara.HavePaperRef); 
	
	
	//标定结果信息 
	if(calipara.isSuccess){
	//	if(PAPER_GAP == Store_Para.Print_Paper_Type_Para.PrintPaperType)
		{
			//写参数入flash
			CalibrateParaWritetoFlash(&calipara);
			//参数更新 至全局变量 
			Store_CalibrationPara = calipara;
		}
//		MyPrintf("PrintPaperType=%d\r\n",Store_Para.Print_Paper_Type_Para.PrintPaperType); 
		Print_Gap_CheckInfo.PaperGap_Gap_NoCheck_ErrorFlag = false;
	}
//	else{
//		Print_Gap_CheckInfo.PaperGap_Gap_NoCheck_ErrorFlag = true;
//	}
//	for(int T =0;T<=20000;T++)
	{
	
		KeyVar.Key_Calibration_Running_Flag = false;  
		KeyVar.Key_Calibration_Finish_Flag = true;  //双击定标完成
	}
	SPI_PrintHead_GPIO_Disability();
	#if 0
		MyPrintf("store finished\r\n");
		MyPrintf("SensorMode:%d,GapInten:%d,GapRef:%d\r\n",
			Store_Para.Print_Paper_Type_Para.PrintPaperType,
			calipara.SelectIndex,
			calipara.GapRef
		);
	#endif 
}




























/******************************************************************************
版权所有:  深圳普实科技有限公司  
文件名:    api_calibration.h   
作者:      wangdy  
创建日期:  2021/6/4
描述:      纸张定标  
其它:      
修改历史:  //修改历史记录列表,每条修改记录应包含修改日期、修改者及修改内容简述
            序号    修改时间    修改人  修改内容
			????    ????/??/??  ??????  参考样式       
******************************************************************************/

/*********************************防止多次编译*********************************/
#ifndef _API_PAPER_CALIBRATION_H
#define _API_PAPER_CALIBRATION_H

/************************************头文件************************************/
#include <stdint.h>
#include <stdbool.h>
#include "bsp_sensor.h"
#include "printerConfig.h"
#include "driver_adc.h"
#include "api_sensorcheck.h"

/************************************宏定义************************************/

//定标最大距离   
#define CALIBRATE_FEEDLIMIT							800   	//100 mm  定标最长 
#define CALIBRATE_CONTINUE_PAPER_FEEDLIMIT			80   	//10 mm  连续纸走定长 
//走纸最大距离  
#define FEEDPAPER_FEEDLIMIT			500	  	//60  mm  走纸最长 

#define CALIBRATE_PAPER_MIN			(MM_DOT * 10)		//纸张部分检测的最小距离 mm
#define CALIBRATE_GAP_MIN  			(MM_DOT)			//间隙部分检测的最小距离 mm
#define CALIBRATE_GAP_MAX 			(MM_DOT * 40)		//间隙部分检测的最大距离 mm 


#define CALI_MAX_SCALE				5  //5
#define CALI_MIN_SCALE				4
#define CALI_SCALE_VALID_SIZE		3

#define CALI_VALUE_TABLE_SIZE		8          //8		//正好1mm 

#define CALI_ADC_MIN_VALUE			200  //0 
#define CALI_ADC_MAX_VALUE			1200  //1200

#define CALI_BLACK_ADC_MIN_VALUE       
#define CALI_BLACK_ADC_MAX_VALUE  


//(225<=GAP_THRESHOLD_DEFAULT<=260) //220  //820 // 1000//间隙纸阈值(间隙处的值)(1号机间隙处阈值201)
#define GAP_THRESHOLD_DEFAULT			201      
#define BLACK_THRESHOLD_DEFAULT			1100      // 黑标纸阈值

#define SELECTED_INDEX_DEFAULT		    1   //2  //4 		  //5
#define BLACK_SELECTED_INDEX_DEFAULT	5        //黑标纸默认索引

												//400     //790     //800     //920     //间隙纸有纸的阈值(1号机间隙有纸阈值是300)(4号机为268)
#define NOPAPER_THRESHOLD_DEFAULT		268  

#define GAP_MIN_MAX_AVE_THRESHOLD		100     //200   //230            //500     //                        (有纸时检测到的值-间隙位检测到的值)      原来500
#define GAP_MIN_MIN_CURRENT_DIFFER_VALUE 10
#define GAP_MIN_MIN_CURRENT_DIFFER_COUNT 5  //

/************************************枚举************************************/


/************************************结构体************************************/

typedef struct{
	uint16_t  Min_ValueTable[CALI_VALUE_TABLE_SIZE];	//最小值表 
	uint16_t  Max_ValueTable[CALI_VALUE_TABLE_SIZE];	//最大值表 
	bool	  ValueTableValidFlag;						//合法标记 
	uint16_t  Min_Ave;									//小表的平均值 
	uint16_t  Max_Ave;									//大表的平均值  
	uint16_t  Min_Min;									//小表里面的最小值 
	uint8_t   Min_Current_Index;						//小表的当前的Index
	uint8_t   Max_Current_Index;						//大表的当前的Index 
	uint16_t  PaperGapThreshold;						//阈值信息 		
	uint16_t  PaperGapDiffer;							//阈值信息 	
	uint16_t  PaperGapMinContinueCount;					//持续小于1个数的计数信息 
}CaliValue_Table_Single_TypeDef;

typedef struct{
	CaliValue_Table_Single_TypeDef   ValueTable[CALI_SCALE_VALID_SIZE];
}CaliValue_Table_TypeDef;

//结果 
typedef struct{
	bool				isValidFlag;					//有效标记 
	uint8_t				SelectedIndex;					//选择的索引  
	int					Gap_RefValue;					//间隙纸对应的阈值信息  
	int 				HavePaper_RefValue;				//无纸对应的值信息 
	int                 Black_RefValue;                  //黑标对应的阈值
}CaliResult_TypeDef;

/**********************************可导出变量**********************************/



/***********************************函数实现***********************************/
void PaperCali_Process();



#endif

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值