#include "../2025_include_user/Oled.hpp"

#define OLED_ADDR 0x3C  // 7位地址（0x78 >> 1）

void OLED::WR_CMD(uint8_t cmd) {
    uint8_t temp[2];
    temp[0] = 0x00;  // Control byte for command
    temp[1] = cmd;

    DL_I2C_fillControllerTXFIFO(I2C_0_INST, temp, 2);
    while (!(DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));

    DL_I2C_startControllerTransfer(I2C_0_INST, OLED_ADDR, DL_I2C_CONTROLLER_DIRECTION_TX, 2);
    while (DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
    while (!(DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));

    DL_I2C_flushControllerTXFIFO(I2C_0_INST);
}

void OLED::WR_DATA(uint8_t data) {
    uint8_t temp[2];
    temp[0] = 0x40;  // Control byte for data
    temp[1] = data;

    DL_I2C_fillControllerTXFIFO(I2C_0_INST, temp, 2);
    while (!(DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));

    DL_I2C_startControllerTransfer(I2C_0_INST, OLED_ADDR, DL_I2C_CONTROLLER_DIRECTION_TX, 2);
    while (DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
    while (!(DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));

    DL_I2C_flushControllerTXFIFO(I2C_0_INST);
}


void OLED::Init() {
    uint8_t CMD_Data[] = {
        0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0xA1, 0xC8, 0xDA,
        0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0x8D, 0x14,
        0xAF
    };

    for (uint8_t i = 0; i < 23; i++) {
        WR_CMD(CMD_Data[i]);
    }
}

void OLED::Clear() {
    for (uint8_t i = 0; i < 8; i++) {
        WR_CMD(0xb0 + i);    // 设置页地址（0~7）
        WR_CMD(0x00);        // 设置显示位置—列低地址
        WR_CMD(0x10);        // 设置显示位置—列高地址
        for (uint8_t n = 0; n < 128; n++) {
            WR_DATA(0);
        }
    }
}

void OLED::Display_On() {
    WR_CMD(0x8D);  // SET DCDC命令
    WR_CMD(0x14);  // DCDC ON
    WR_CMD(0xAF);  // DISPLAY ON, 打开显示
}

void OLED::Display_Off() {
    WR_CMD(0x8D);  // SET DCDC命令
    WR_CMD(0x10);  // DCDC OFF
    WR_CMD(0xAE);  // DISPLAY OFF，关闭显示
}

void OLED::Set_Pos(uint8_t x, uint8_t y) {
    WR_CMD(0xb0 + y);    // 设置页地址（0~7）
    WR_CMD(((x & 0xf0) >> 4) | 0x10); // 设置显示位置—列高地址
    WR_CMD(x & 0x0f);    // 设置显示位置—列低地址
}

unsigned int OLED::oled_pow(uint8_t m, uint8_t n) {
    unsigned int result = 1;
    while (n--) result *= m;
    return result;
}

void OLED::ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size, uint8_t Color_Turn) {
    uint8_t c = chr - ' '; // 得到偏移后的值
    if (x > 128 - 1) { x = 0; y = y + 2; }
    if (Char_Size == 16) {
        Set_Pos(x, y);
        for (uint8_t i = 0; i < 8; i++) {
            if (Color_Turn)
                WR_DATA(~F8X16[c * 16 + i]);
            else
                WR_DATA(F8X16[c * 16 + i]);
        }
        Set_Pos(x, y + 1);
        for (uint8_t i = 0; i < 8; i++) {
            if (Color_Turn)
                WR_DATA(~F8X16[c * 16 + i + 8]);
            else
                WR_DATA(F8X16[c * 16 + i + 8]);
        }
    } else {
        Set_Pos(x, y);
        for (uint8_t i = 0; i < 6; i++) {
            if (Color_Turn)
                WR_DATA(~F6x8[c][i]);
            else
                WR_DATA(F6x8[c][i]);
        }
    }
}

void OLED::ShowString(uint8_t x, uint8_t y, char* chr, uint8_t Char_Size, uint8_t Color_Turn) {
    uint8_t j = 0;
    while (chr[j] != '\0') {
        ShowChar(x, y, chr[j], Char_Size, Color_Turn);
        if (Char_Size == 12) // 6X8的字体列加6，显示下一个字符
            x += 6;
        else // 8X16的字体列加8，显示下一个字符
            x += 8;

        if (x > 122 && Char_Size == 12) // TextSize6x8如果一行不够显示了，从下一行继续显示
        {
            x = 0;
            y++;
        }
        if (x > 120 && Char_Size == 16) // TextSize8x16如果一行不够显示了，从下一行继续显示
        {
            x = 0;
            y++;
        }
        j++;
    }
}

void OLED::ShowNum(uint8_t x, uint8_t y, unsigned int num, uint8_t len, uint8_t size2, uint8_t Color_Turn) {
    uint8_t t, temp;
    uint8_t enshow = 0;
    for (t = 0; t < len; t++) {
        temp = (num / oled_pow(10, len - t - 1)) % 10;
        if (enshow == 0 && t < (len - 1)) {
            if (temp == 0) {
                ShowChar(x + (size2 / 2) * t, y, ' ', size2, Color_Turn);
                continue;
            } else enshow = 1;
        }
        ShowChar(x + (size2 / 2) * t, y, temp + '0', size2, Color_Turn);
    }
}

void OLED::ShowDecimal(uint8_t x, uint8_t y, float num, uint8_t z_len, uint8_t f_len, uint8_t size2, uint8_t Color_Turn) {
    uint8_t t, temp, i = 0; // i为负数标志位
    uint8_t enshow;
    int z_temp, f_temp;
    if (num < 0) {
        z_len += 1;
        i = 1;
        num = -num;
    }
    z_temp = (int)num;
    // 整数部分
    for (t = 0; t < z_len; t++) {
        temp = (z_temp / oled_pow(10, z_len - t - 1)) % 10;
        if (enshow == 0 && t < (z_len - 1)) {
            if (temp == 0) {
                ShowChar(x + (size2 / 2) * t, y, ' ', size2, Color_Turn);
                continue;
            } else
                enshow = 1;
        }
        ShowChar(x + (size2 / 2) * t, y, temp + '0', size2, Color_Turn);
    }
    // 小数点
    ShowChar(x + (size2 / 2) * (z_len), y, '.', size2, Color_Turn);

    f_temp = (int)((num - z_temp) * (oled_pow(10, f_len)));
    // 小数部分
    for (t = 0; t < f_len; t++) {
        temp = (f_temp / oled_pow(10, f_len - t - 1)) % 10;
        ShowChar(x + (size2 / 2) * (t + z_len) + 5, y, temp + '0', size2, Color_Turn);
    }
    if (i == 1) // 如果为负，就将最前的一位赋值‘-’
    {
        ShowChar(x, y, '-', size2, Color_Turn);
        i = 0;
    }
}

void OLED::ShowChinese(uint8_t x, uint8_t y, uint8_t no, uint8_t Color_Turn) {
    uint8_t t = 0;
    Set_Pos(x, y);
    for (t = 0; t < 16; t++) {
        if (Color_Turn)
            WR_DATA(~Hzk[2 * no][t]); // 显示汉字的上半部分
        else
            WR_DATA(Hzk[2 * no][t]); // 显示汉字的上半部分
    }

    Set_Pos(x, y + 1);
    for (t = 0; t < 16; t++) {
        if (Color_Turn)
            WR_DATA(~Hzk[2 * no + 1][t]); // 显示汉字的上半部分
        else
            WR_DATA(Hzk[2 * no + 1][t]); // 显示汉字的上半部分
    }
}

void OLED::DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t* BMP, uint8_t Color_Turn) {
    uint32_t j = 0;
    uint8_t x = 0, y = 0;

    if (y1 % 8 == 0)
        y = y1 / 8;
    else
        y = y1 / 8 + 1;
    for (y = y0; y < y1; y++) {
        Set_Pos(x0, y);
        for (x = x0; x < x1; x++) {
            if (Color_Turn)
                WR_DATA(~BMP[j++]); // 显示反相图片
            else
                WR_DATA(BMP[j++]); // 显示图片
        }
    }
}

void OLED::HorizontalShift(uint8_t direction) {
    WR_CMD(0x2e); // 停止滚动
    WR_CMD(direction); // 设置滚动方向
    WR_CMD(0x00); // 虚拟字节设置，默认为0x00
    WR_CMD(0x00); // 设置开始页地址
    WR_CMD(0x07); // 设置每个滚动步骤之间的时间间隔的帧频
    WR_CMD(0x07); // 设置结束页地址
    WR_CMD(0x00); // 虚拟字节设置，默认为0x00
    WR_CMD(0xff); // 虚拟字节设置，默认为0xff
    WR_CMD(0x2f); // 开启滚动-0x2f，禁用滚动-0x2e，禁用需要重写数据
}

void OLED::Some_HorizontalShift(uint8_t direction, uint8_t start, uint8_t end) {
    WR_CMD(0x2e); // 停止滚动
    WR_CMD(direction); // 设置滚动方向
    WR_CMD(0x00); // 虚拟字节设置，默认为0x00
    WR_CMD(start); // 设置开始页地址
    WR_CMD(0x07); // 设置每个滚动步骤之间的时间间隔的帧频
    WR_CMD(end); // 设置结束页地址
    WR_CMD(0x00); // 虚拟字节设置，默认为0x00
    WR_CMD(0xff); // 虚拟字节设置，默认为0xff
    WR_CMD(0x2f); // 开启滚动-0x2f，禁用滚动-0x2e，禁用需要重写数据
}

void OLED::VerticalAndHorizontalShift(uint8_t direction) {
    WR_CMD(0x2e); // 停止滚动
    WR_CMD(direction); // 设置滚动方向
    WR_CMD(0x01); // 虚拟字节设置
    WR_CMD(0x00); // 设置开始页地址
    WR_CMD(0x07); // 设置每个滚动步骤之间的时间间隔的帧频
    WR_CMD(0x07); // 设置结束页地址
    WR_CMD(0x01); // 垂直滚动偏移量
    WR_CMD(0x00); // 虚拟字节设置，默认为0x00
    WR_CMD(0xff); // 虚拟字节设置，默认为0xff
    WR_CMD(0x2f); // 开启滚动-0x2f，禁用滚动-0x2e，禁用需要重写数据
}

void OLED::DisplayMode(uint8_t mode) {
    WR_CMD(mode);
}

void OLED::IntensityControl(uint8_t intensity) {
    WR_CMD(0x81);
    WR_CMD(intensity);
}