#include <STC8H.H>
#include <intrins.h>

/*--- 函数声明 ---*/
void Init_GPIO(void);
void Init_Interrupt(void);
void HC595_Send4Digits(unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4);
void UpdateDisplay(void);
void EEPROM_EraseSector(unsigned int addr);
void EEPROM_Write(unsigned int addr, unsigned char *buf, unsigned char len);
void EEPROM_Read(unsigned int addr, unsigned char *buf, unsigned char len);
void SaveSettings(void);
void LoadSettings(void);
void ApplyCurrentOutput(void);
void ScheduleSave(void); // 新增：调度保存操作

/*--- 全局变量定义 ---*/
volatile unsigned char count = 0x80;        // count=0对应127.5，count=255对应0.0
volatile unsigned char current_output = 0x80;
volatile unsigned char delayed_bits = 0;
volatile bit delay_active = 0;
volatile unsigned char delay_counter = 0;
volatile bit output_enabled = 1;

/*--- 锁定机制相关变量 ---*/
volatile unsigned int lock_timer = 10000;
volatile bit keys_locked = 1;

/*--- 按键状态控制变量 ---*/
volatile unsigned char key1_state = 0, key2_state = 0, key3_state = 0;
volatile unsigned int key1_counter = 0, key2_counter = 0, key3_counter = 0;

/*--- 数码管驱动部分 ---*/
sbit DS = P3^0;
sbit SHCP = P3^4;
sbit STCP = P3^5;
code unsigned char SegCode[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99,  // 0-4
    0x92, 0x82, 0xF8, 0x80, 0x90,  // 5-9
    0xBF   // 横杠'-'
};
volatile bit display_refresh = 1;

/*--- EEPROM相关定义 ---*/
#define EEPROM_BASE_ADDR 0x0000  // EEPROM起始地址
#define SETTINGS_SIZE 4          // 需要保存的设置数据大小

/*--- EEPROM保存相关变量 ---*/
volatile bit save_pending = 0;   // 保存操作待处理标志
volatile unsigned int save_delay = 0; // 保存延时计数器

/******************************
 * EEPROM扇区擦除函数
 ******************************/
void EEPROM_EraseSector(unsigned int addr) {
    IAP_CONTR = 0x80;           // 使能IAP
    IAP_TPS = 12;               // 设置等待参数(系统时钟/12)
    IAP_CMD = 0x03;             // 扇区擦除命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_TRIG = 0x5A;            // 触发命令
    IAP_TRIG = 0xA5;
    _nop_();_nop_();_nop_();_nop_();
    IAP_CONTR = 0x00;           // 关闭IAP
    IAP_CMD = 0x00;             // 清除命令
}

/******************************
 * EEPROM写函数
 ******************************/
void EEPROM_Write(unsigned int addr, unsigned char *buf, unsigned char len) {
    unsigned char i;
    
    // 先擦除扇区
    EEPROM_EraseSector(addr);
    
    IAP_CONTR = 0x80;           // 使能IAP
    IAP_TPS = 12;               // 设置等待参数(系统时钟/12)
    
    for(i = 0; i < len; i++) {
        IAP_CMD = 0x02;         // 写命令
        IAP_ADDRH = (addr + i) >> 8;
        IAP_ADDRL = (addr + i) & 0xFF;
        IAP_DATA = buf[i];      // 写入数据
        IAP_TRIG = 0x5A;        // 触发命令
        IAP_TRIG = 0xA5;
        _nop_();_nop_();_nop_();_nop_(); // 等待写入完成
    }
    IAP_CONTR = 0x00;           // 关闭IAP
    IAP_CMD = 0x00;             // 清除命令
}

/******************************
 * EEPROM读函数
 ******************************/
void EEPROM_Read(unsigned int addr, unsigned char *buf, unsigned char len) {
    unsigned char i;
    IAP_CONTR = 0x80;           // 使能IAP
    IAP_TPS = 12;               // 设置等待参数(系统时钟/12)
    
    for(i = 0; i < len; i++) {
        IAP_CMD = 0x01;         // 读命令
        IAP_ADDRH = (addr + i) >> 8;
        IAP_ADDRL = (addr + i) & 0xFF;
        IAP_TRIG = 0x5A;        // 触发命令
        IAP_TRIG = 0xA5;
        _nop_();_nop_();_nop_();_nop_(); // 等待读取完成
        buf[i] = IAP_DATA;      // 读取数据
    }
    IAP_CONTR = 0x00;           // 关闭IAP
    IAP_CMD = 0x00;             // 清除命令
}

/******************************
 * 保存设置到EEPROM
 ******************************/
void SaveSettings(void) {
    unsigned char buf[SETTINGS_SIZE];
    
    buf[0] = count;
    buf[1] = output_enabled;
    buf[2] = 0x5A; // 魔数1，用于验证数据有效性
    buf[3] = 0xA5; // 魔数2，用于验证数据有效性
    
    EEPROM_Write(EEPROM_BASE_ADDR, buf, SETTINGS_SIZE);
}

/******************************
 * 从EEPROM加载设置
 ******************************/
void LoadSettings(void) {
    unsigned char buf[SETTINGS_SIZE];
    
    EEPROM_Read(EEPROM_BASE_ADDR, buf, SETTINGS_SIZE);
    
    // 验证魔数是否正确
    if(buf[2] == 0x5A && buf[3] == 0xA5) {
        // 魔数正确，使用保存的值
        count = buf[0];
        current_output = count;
        output_enabled = buf[1];
    } else {
        // 魔数错误，使用默认值
        count = 0x80;
        current_output = 0x80;
        output_enabled = 1;
        // 设置保存标志，将在主循环中保存默认值
        save_pending = 1;
    }
}

/******************************
 * 调度保存操作
 ******************************/
void ScheduleSave(void) {
    save_pending = 1;
    save_delay = 1000; // 1秒后保存
}

/******************************
 * 应用当前输出到LED
 ******************************/
void ApplyCurrentOutput(void) {
    if(output_enabled) {
        P1 = current_output;
    } else {
        P1 = 0x00;
    }
}

/******************************
 * GPIO初始化函数
 ******************************/
void Init_GPIO(void) {
    P1M0 = 0xFF;  // P1推挽输出
    P1M1 = 0x00;
    P1 = 0x80;    // 初始值

    P3M0 = 0x31;  // P3.0,P3.4,P3.5推挽输出
    P3M1 = 0x00;
    P3PU = 0xCE;  // P3.1,P3.6,P3.7上拉
}

/******************************
 * 中断初始化函数
 ******************************/
void Init_Interrupt(void) {
    IT0 = 1;     // 下降沿触发
    EX0 = 1;     // 使能INT0
    
    TMOD &= 0xF0;
    TMOD |= 0x01;  // 定时器0模式1
    TH0 = (65536 - 1000) >> 8;
    TL0 = (65536 - 1000) & 0xFF;
    ET0 = 1;
    EA = 1;
    TR0 = 1;
}

/******************************
 * 74HC595驱动函数
 ******************************/
void HC595_Send4Digits(unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4) {
    unsigned char i;
    unsigned long data_packet = ((unsigned long)d1 << 24) | 
                               ((unsigned long)d2 << 16) |
                               ((unsigned long)d3 << 8) | 
                               d4;

    for(i = 0; i < 32; i++) {
        DS = (data_packet & 0x80000000) ? 1 : 0;
        data_packet <<= 1;
        SHCP = 0;
        _nop_();_nop_();
        SHCP = 1;
    }
    STCP = 0;
    _nop_();_nop_();
    STCP = 1;
}

/******************************
 * 显示更新函数（千位0显示为横杠）
 ******************************/
void UpdateDisplay(void) {
    static unsigned int last_count = 0xFFFF;
    static bit last_enabled = 2;
    unsigned int value_x10;
    unsigned char d1, d2, d3, d4;
    unsigned char seg1, seg2, seg3, seg4;
    
    if(last_count == count && last_enabled == output_enabled) 
        return;
    
    last_count = count;
    last_enabled = output_enabled;
    
    if(!output_enabled) {
        HC595_Send4Digits(0xBF, 0xBF, 0xBF, 0xBF);
        return;
    }
    
    // 计算显示值：127.5 - count*0.5 → 格式XX.X
    value_x10 = 1275 - 5 * count;
    d1 = (value_x10 / 1000) % 10;    // 千位
    d2 = (value_x10 % 1000) / 100;   // 百位
    d3 = (value_x10 % 100) / 10;     // 十位（带小数点）
    d4 = value_x10 % 10;             // 个位

    // 千位0显示为横杠，数值0时完全消隐
    if(value_x10 == 0) {
        seg1 = 0xFF;      // 千位消隐
        seg2 = 0xFF;      // 百位消隐
        seg3 = SegCode[0] & 0x7F;
        seg4 = SegCode[0];
    } else {
        seg1 = (d1 == 0) ? SegCode[10] : SegCode[d1]; // 千位0显示横杠
        seg2 = (d1 == 0 && d2 == 0) ? 0xFF : SegCode[d2];
        seg3 = SegCode[d3] & 0x7F;
        seg4 = SegCode[d4];
    }

    HC595_Send4Digits(seg1, seg2, seg3, seg4);
}

/******************************
 * 定时器0中断服务程序（完整逻辑）
 ******************************/
void timer0_isr(void) interrupt 1 {
    TH0 = (65536 - 1000) >> 8;
    TL0 = (65536 - 1000) & 0xFF;

    // 保存设置延时处理
    if(save_pending) {
        if(save_delay > 0) {
            save_delay--;
        }
        // 不再在中断中调用SaveSettings，将在主循环中处理
    }
   
    // 锁定计时处理
    if(keys_locked) {
        if(lock_timer > 0) lock_timer--;
        else keys_locked = 0;
    }

    // 消隐延迟处理
    if(delay_active) {
        if(delay_counter > 0) delay_counter--;
        else {
            current_output |= delayed_bits;
            P1 = current_output;
            delayed_bits = 0;
            delay_active = 0;
        }
    }

    // 按键扫描逻辑
    if(!keys_locked) {
        // 按键1（P3.6）增加count
        if (!(P3 & 0x40)) {
            if (key1_state == 0) {
                if(++key1_counter >= 20) {
                    key1_state = 1;
                    key1_counter = 0;
                    if(count < 0xFF) count++;
                    display_refresh = 1;  // 手动触发刷新
                    ScheduleSave();       // 调度保存操作
                }
            } else {
                if(++key1_counter >= 500) {
                    if(count < 0xFF) count++;
                    display_refresh = 1;  // 手动触发刷新
                    key1_counter = 400;
                    ScheduleSave();       // 调度保存操作
                }
            }
        } else {
            key1_state = 0;
            key1_counter = 0;
        }

        // 按键2（P3.7）减少count
        if (!(P3 & 0x80)) {
            if (key2_state == 0) {
                if(++key2_counter >= 20) {
                    key2_state = 1;
                    key2_counter = 0;
                    if(count > 0) count--;
                    display_refresh = 1;  // 手动触发刷新
                    ScheduleSave();       // 调度保存操作
                }
            } else {
                if(++key2_counter >= 500) {
                    if(count > 0) count--;
                    display_refresh = 1;  // 手动触发刷新
                    key2_counter = 400;
                    ScheduleSave();       // 调度保存操作
                }
            }
        } else {
            key2_state = 0;
            key2_counter = 0;
        }
    }

    // 按键3（P3.1）
    if (!(P3 & 0x02)) {
        if (key3_state == 0) {
            if(++key3_counter >= 20) {
                key3_state = 1;
                key3_counter = 0;
                output_enabled = !output_enabled;
                display_refresh = 1;  // 手动触发刷新
                ScheduleSave();       // 调度保存操作
                ApplyCurrentOutput(); // 立即应用输出状态
            }
        }
    } else {
        key3_state = 0;
        key3_counter = 0;
    }
}

/******************************
 * 外部中断0服务程序
 ******************************/
void exint0() interrupt 0 {
    if (P3 & 0x08) {       // 方向判断
        if (count > 0) count--;
    } else {
        if (count < 0xFF) count++;
    }
    display_refresh = 1;
    
    // 调度保存操作
    ScheduleSave();
}

/******************************
 * 主函数
 ******************************/
void main(void) {
    Init_GPIO();
    
    // 加载保存的设置
    LoadSettings();
    
    // 立即应用保存的输出状态到LED
    ApplyCurrentOutput();
    
    Init_Interrupt();
    UpdateDisplay();

    while(1) {
        // LED输出控制
        if(output_enabled) {
            if(current_output != count) {
                unsigned char changed = current_output ^ count;
                current_output = count;
                P1 = current_output & ~(changed & count);
                delayed_bits = changed & count;
                delay_counter = 5;
                delay_active = 1;
            }
        } else {
            P1 = 0x00;
        }

        // 显示刷新处理
        if(display_refresh) {
            display_refresh = 0;
            UpdateDisplay();
        }
        
        // 保存设置处理（在主循环中执行，避免重入问题）
        if(save_pending && save_delay == 0) {
            save_pending = 0;
            SaveSettings();
        }
        
        _nop_();
    }
}