Преглед изворни кода

添加lcd屏驱动,继续实现power接口

guohui пре 1 година
родитељ
комит
7ce50173f6

+ 3 - 4
f407/applications/datadef.h

@@ -315,17 +315,16 @@ typedef struct board_data {
     uint8_t             addr;
     uint8_t             chs;
     uint8_t             sw;                     //开关监测状态
+    uint8_t             ch0;                    //board ch start
     uint8_t             ph_loss;
     board_info_t        info;
     power_ch_t          *pch;                   //根据实际通道数申请连续内存
 }board_data_t;
 
 typedef struct {
-    uint8_t             chs;                    //所有控制板的总通道数
-    power_ch_t          **pch;                  //动态指针
     
-    uint8_t             cnt;
-    board_data_t        *pbrd[BRD_MAX];
+    
+    
 }board_all_t;
 
 typedef struct {

+ 317 - 258
f407/applications/power.c

@@ -7,17 +7,21 @@
 #include "thread.h"
 #include "datadef.h"
 
-typedef struct {
-    int8_t  type;
-    uint8_t chs;
-}ch_info_t;
 typedef struct {
     void*           mb;
+    lock_t          lck;
+    uint8_t         cur_addr;
+    
+    uint8_t         chs;                    //所有控制板的总通道数
+    power_ch_t      **pch;                  //动态指针
     
+    uint8_t         cnt;                    //实际扫到的板子个数,不可大于BRD_MAX
+    uint8_t         brd_max;
+    board_data_t    *pbrd[BRD_MAX+1];       //通过modbus地址索引
+    
+    board_key_t     key[BRD_MAX+1];
     power_total_t   ttl;
-    board_all_t     all;
     
-    lock_t          lck;
 }power_handle_t;
 power_handle_t pwrHandle={0};
 
@@ -40,40 +44,28 @@ static int write_reg(power_handle_t *h, uint8_t addr, uint16_t reg, uint16_t *da
     return mb_write(h->mb, addr, reg, data, cnt);
 }
 ////////////////////////////////////////////////////////////////////
-static int get_info(power_handle_t *h, uint8_t addr, board_key_t *info)
+static int get_key(power_handle_t *h, uint8_t addr, board_key_t *key)
 {
     int i,r=-1;
     uint16_t tmp=0;
     
     r = read_reg(h, addr, POWER_DC_INFO, &tmp, 1);
     if(r==0) {
-        info->type = (tmp>>8)&0xFF;
-        info->chs = tmp&0xFF;
+        key->type = (tmp>>8)&0xFF;
+        key->chs = tmp&0xFF;
         return 0;
     }
     
     r = read_reg(h, addr, POWER_AC_GET_INFO, &tmp, 1);
     if(r==0) {
-        info->type = (tmp>>8)&0xFF;
-        info->chs = tmp&0xFF;
+        key->type = (tmp>>8)&0xFF;
+        key->chs = tmp&0xFF;
     }
     
     return r;
 }
-static int get_ch(power_handle_t *h, int ch, power_ch_t *pch)
-{
-    if(!pch || !h->all.pch || !h->all.chs || !h->all.pch[ch]) {
-        lock_d_release(h->lck);
-        return -1;
-    }
-    *pch = *h->all.pch[ch];
-    
-    return 0;
-}
 ////////////////////////////////////////////////////////////////
 
-
-
 static int set_kb_value(power_handle_t *h, int type, int addr, kb_val_t *kv)
 {
     switch(type) {
@@ -155,7 +147,6 @@ static int set_kb_value(power_handle_t *h, int type, int addr, kb_val_t *kv)
 }
 static int reset_consump(power_handle_t *h, int type, int addr)
 {
-    
     switch(type) {
         case AC_SINGLE_S_TYPE:
         case AC_SINGLE_B_TYPE:
@@ -187,20 +178,69 @@ static int reset_consump(power_handle_t *h, int type, int addr)
 
 
 //////////////////////////////////////////////////////////////////
-static int get_board(power_handle_t *h, uint8_t addr, board_data_t *pbrd)
+static board_data_t* board_next(power_handle_t *h)
+{
+    uint8_t addr=h->cur_addr;
+    while(1) {
+        h->cur_addr++;
+        if(h->cur_addr>h->brd_max) {
+            h->cur_addr = 1;
+        }
+        else if(h->cur_addr==addr) {
+            break;
+        }
+        if(h->pbrd[h->cur_addr]) {
+            return h->pbrd[h->cur_addr];
+        }
+    }
+    return NULL;
+}
+static uint8_t get_ch_idx(board_data_t *pbrd, uint8_t sch)
 {
-    int r,i,j;
-    alarm_t alarm;
+    uint8_t ch=0;
+    uint8_t pwr_type=paras_get()->prod.pwr_type;
+    if(pbrd->type==TREE_AC_TYPE) {
+        if(pwr_type == PDU_AC_I3O3) {
+            ch = pbrd->ch0 + sch/3;
+        }
+        else {
+            ch = pbrd->ch0 + sch;
+        }
+    }
+    else {
+        ch = pbrd->ch0 + sch;
+    }
+    
+    return ch;
+}
+static int threshold_proc(board_data_t *pbrd)
+{
+    int i,j,r=-1;
+    
+    
+    
+    return 0;
+}
+static int board_query(power_handle_t *h)
+{
+    int i,j,r=-1;
     uint16_t offset,tmp[144];
+    board_data_t *pbrd=NULL;
     
-    switch(pbrd->type) {
-        case AC_SINGLE_S_TYPE:
-        case AC_SINGLE_B_TYPE:
-        {
-            uint32_t val;
-            
-            r = read_reg(h, pbrd->addr, POWER_AC_CUR_INFO_L, tmp, pbrd->chs);
-            if(r==0 && pbrd->pch) {
+    lock_d_hold(h->lck);
+    pbrd = board_next(h);
+    if(pbrd) {
+        switch(pbrd->type) {
+            case AC_SINGLE_S_TYPE:
+            case AC_SINGLE_B_TYPE:
+            {
+                uint32_t val;
+                r = read_reg(h, pbrd->addr, POWER_AC_CUR_INFO_L, tmp, pbrd->chs);
+                if (r<0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
                 for (i=0; i<pbrd->chs; i++) {
                     int idx = i * 12;
                     // 解电压数据
@@ -222,15 +262,13 @@ static int get_board(power_handle_t *h, uint8_t addr, board_data_t *pbrd)
                     val = (tmp[11 + idx] << 16) | tmp[10 + idx];
                     pbrd->pch[i].power[0].factor = val / 1000.0;
                 }
-            }
-            
-            r = read_reg(h, pbrd->addr, POWER_AC_STAT_INFO_L, tmp, pbrd->chs);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            
-            if(pbrd->pch) {
+                
+                r = read_reg(h, pbrd->addr, POWER_AC_STAT_INFO_L, tmp, pbrd->chs);
+                if (r<0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+ 
                 for (i=0; i<pbrd->chs; i++) {
                     pbrd->pch[i].power[0].status = tmp[i] & (0x01);
                     pbrd->pch[i].alarm.v_upper   = tmp[i] & ALARM_V_UPPER;
@@ -241,188 +279,188 @@ static int get_board(power_handle_t *h, uint8_t addr, board_data_t *pbrd)
                     pbrd->pch[i].alarm.ph_loss   = 0;
                 }
             }
-        }
-        break;
+            break;
+
+            case DCPDU_TYPE:
+            {
+                uint32_t flag;
+                offset = POWER_DC_OUT_INFO + 16;
+                uint16_t *ptmp = tmp + 32;
+                r = read_reg(h, pbrd->addr, offset, ptmp, 32);
+                if (r<0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                for (i = 0; i < pbrd->chs; i++) {
+                    int Index = i * 8;
+                    // 解电压数据
+                    float value = (tmp[1 + Index] << 16) + tmp[0 + Index];
+                    pbrd->pch[i].power[0].voltage = value / 1000.0;
+                    // 解电流数据
+                    value = (tmp[3 + Index] << 16) + tmp[2 + Index];
+                    pbrd->pch[i].power[0].current = value / 1000.0;
+                    // 解功率数据
+                    value = (tmp[5 + Index] << 16) + tmp[4 + Index];
+                    pbrd->pch[i].power[0].power = value / 1000.0;
 
-        case DCPDU_TYPE:
-        {
-            uint32_t flag;
-            offset = POWER_DC_OUT_INFO + 16;
-            uint16_t *ptmp = tmp + 32;
-            r = read_reg(h, pbrd->addr, offset, ptmp, 32);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
+                    value = (tmp[7 + Index] << 16) + tmp[6 + Index];
+                    pbrd->pch[i].power[0].consump = value / 1000.0;
 
-            for (i = 0; i < pbrd->chs; i++) {
-                int Index = i * 8;
-                // 解电压数据
-                float value = (tmp[1 + Index] << 16) + tmp[0 + Index];
-                pbrd->pch[i].power[0].voltage = value / 1000.0;
-                // 解电流数据
-                value = (tmp[3 + Index] << 16) + tmp[2 + Index];
-                pbrd->pch[i].power[0].current = value / 1000.0;
-                // 解功率数据
-                value = (tmp[5 + Index] << 16) + tmp[4 + Index];
-                pbrd->pch[i].power[0].power = value / 1000.0;
-
-                value = (tmp[7 + Index] << 16) + tmp[6 + Index];
-                pbrd->pch[i].power[0].consump = value / 1000.0;
-
-                pbrd->pch[i].power[0].freq = 0;
-                pbrd->pch[i].power[0].factor = 1;
-            }
+                    pbrd->pch[i].power[0].freq = 0;
+                    pbrd->pch[i].power[0].factor = 1;
+                }
 
-            offset = POWER_DC_STAT_INFO;
-            
-            r = read_reg(h, pbrd->addr, offset, tmp, 2);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
+                offset = POWER_DC_STAT_INFO;
+                r = read_reg(h, pbrd->addr, offset, tmp, 2);
+                if (r<0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                for (i = 0; i < pbrd->chs; i++) {
+                    flag = (tmp[1] << 16) + tmp[0];
+                    pbrd->pch[i].power[0].status = (flag >> i) & 0x1;
+                }
+                
+                
+                // 获取报警状态
+                offset = POWER_DC_WARNING;
+                r = read_reg(h, pbrd->addr, offset, tmp, 16);
+                if (r<0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                for (i = 0; i < pbrd->chs; i++) {
+                    int Index = i * 2;
+                    pbrd->pch[i].alarm.v_upper = tmp[0+Index] & BIT(0);
+                    pbrd->pch[i].alarm.v_lower = tmp[0+Index] & BIT(1);
+                    pbrd->pch[i].alarm.c_upper = tmp[0+Index] & BIT(2);
+                    pbrd->pch[i].alarm.p_upper = tmp[0+Index] & BIT(3);
+                    pbrd->pch[i].alarm.w_upper = tmp[0+Index] & BIT(4);
+                }
             }
+            break;
             
-            for (i = 0; i < pbrd->chs; i++) {
-                flag = (tmp[1] << 16) + tmp[0];
-                pbrd->pch[i].power[0].status = (flag >> i) & 0x1;
-            }
-            // 获取报警状态
-            offset = POWER_DC_WARNING;
-            r = read_reg(h, pbrd->addr, offset, tmp, 16);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
+            case TREE_AC_TYPE:
+            {
+                uint8_t v=0;
+               
+                offset = POWER_AC3_OUT_INFO;
+                r = read_reg(h, pbrd->addr, offset, tmp, 80);
+                if (r < 0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                offset = POWER_AC3_OUT_INFO+40;
+                uint16_t* ptmp=tmp+80;
+                r = read_reg(h, pbrd->addr, offset, ptmp, 64);
+                if (r < 0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                for (i=0; i<pbrd->chs; i++) {
+                    int Index = i * 16;
+                    // 解电压数据
+                    float value = (tmp[1+Index] << 16) + tmp[0+Index];
+                    pbrd->pch[i].power[0].voltage = value / 1000.0f;
+                    // 解电流数据
+                    value = (tmp[3+Index] << 16) + tmp[2+Index];
+                    pbrd->pch[i].power[0].current = value / 1000.0f;
+                    // 解功率数据
+                    value = (tmp[5+Index] << 16) + tmp[4+Index];
+                    pbrd->pch[i].power[0].power = value / 1000.0f;
+                    // 无功
+                    value = (tmp[7+Index] << 16) + tmp[6+Index];
+                    // 视在功率
+                    value = (tmp[9+Index] << 16) + tmp[8+Index];
+                    // 解频率数据
+                    value = (tmp[11+Index] << 16) + tmp[10+Index];
+                    pbrd->pch[i].power[0].freq = value / 1000.0f;
+                    // 解耗电量数据
+                    value = (tmp[13+Index] << 16) + tmp[12+Index];
+                    pbrd->pch[i].power[0].consump = value / 1000.0f;
+                    // 解功率因素数据
+                    value = (tmp[15+Index] << 16) + tmp[14+Index];
+                    pbrd->pch[i].power[0].factor = value / 1023.0f;
+                }
+                
+                //获取通道开关状态及零线状态 
+                offset = POWER_AC3_OUT_ENABLE;
+                r = read_reg(h, pbrd->addr, offset, tmp, 20);
+                if (r < 0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                for (i=0; i<pbrd->chs; i++) {
+                    int Index = i * 2;
+                    pbrd->pch[i].power[0].status = tmp[0+Index] & 0x01;
+                    pbrd->pch[i].power[0].nwire  = tmp[18] & 0x01;
+                }
+                
+                //获取故障状态
+                offset = POWER_AC3_OUT_ERROR;
+                r = read_reg(h, pbrd->addr, offset, tmp, 18);
+                if (r < 0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                for (i=0; i<pbrd->chs; i++) {
+                    int Index = i * 2;
+                    pbrd->pch[i].alarm.v_upper = tmp[0+Index] & BIT(0);
+                    pbrd->pch[i].alarm.v_lower = tmp[0+Index] & BIT(1);
+                    pbrd->pch[i].alarm.c_upper = tmp[0+Index] & BIT(2);
+                    pbrd->pch[i].alarm.p_upper = tmp[0+Index] & BIT(3);
+                    pbrd->pch[i].alarm.w_upper = tmp[0+Index] & BIT(4);
+                }
+                
+                offset = POWER_AC3_ALARM_MISSING_PH;
+                r = read_reg(h, pbrd->addr, offset, tmp, pbrd->chs);
+                if (r < 0) {
+                    LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
+                    break;
+                }
+                
+                v = 0;
+                for(i = 0; i < 3; i++) {
+                    if(tmp[i * 2]>0) {
+                        v |= 1<<i;
+                    }
+                }
+                pbrd->ph_loss = v;
             }
+            break;
             
-            for (i = 0; i < pbrd->chs; i++) {
-                int Index = i * 2;
-                pbrd->pch[i].alarm.v_upper = tmp[0+Index] & BIT(0);
-                pbrd->pch[i].alarm.v_lower = tmp[0+Index] & BIT(1);
-                pbrd->pch[i].alarm.c_upper = tmp[0+Index] & BIT(2);
-                pbrd->pch[i].alarm.p_upper = tmp[0+Index] & BIT(3);
-                pbrd->pch[i].alarm.w_upper = tmp[0+Index] & BIT(4);
-            }
+            case AC_MULTI_S_TYPE:
+            case AC_MULTI_B_TYPE:
+            case DC_OUT_TYPE:
+            case DC_IN_TYPE:
+            default:
+            break;
         }
-        break;
         
-        case TREE_AC_TYPE:
-        {
-            uint8_t v=0;
-           
-            offset = POWER_AC3_OUT_INFO;
-            r = read_reg(h, pbrd->addr, offset, tmp, 80);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            
-            offset = POWER_AC3_OUT_INFO+40;
-            uint16_t* ptmp=tmp+80;
-            r = read_reg(h, pbrd->addr, offset, ptmp, 64);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            
-            for (i=0; i<pbrd->chs; i++) {
-                int Index = i * 16;
-                // 解电压数据
-                float value = (tmp[1+Index] << 16) + tmp[0+Index];
-                pbrd->pch[i].power[0].voltage = value / 1000.0f;
-                // 解电流数据
-                value = (tmp[3+Index] << 16) + tmp[2+Index];
-                pbrd->pch[i].power[0].current = value / 1000.0f;
-                // 解功率数据
-                value = (tmp[5+Index] << 16) + tmp[4+Index];
-                pbrd->pch[i].power[0].power = value / 1000.0f;
-                // 无功
-                value = (tmp[7+Index] << 16) + tmp[6+Index];
-                // 视在功率
-                value = (tmp[9+Index] << 16) + tmp[8+Index];
-                // 解频率数据
-                value = (tmp[11+Index] << 16) + tmp[10+Index];
-                pbrd->pch[i].power[0].freq = value / 1000.0f;
-                // 解耗电量数据
-                value = (tmp[13+Index] << 16) + tmp[12+Index];
-                pbrd->pch[i].power[0].consump = value / 1000.0f;
-                // 解功率因素数据
-                value = (tmp[15+Index] << 16) + tmp[14+Index];
-                pbrd->pch[i].power[0].factor = value / 1023.0f;
-            }
-            
-            //获取通道开关状态及零线状态 
-            offset = POWER_AC3_OUT_ENABLE;
-            r = read_reg(h, pbrd->addr, offset, tmp, 20);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            for (i=0; i<pbrd->chs; i++) {
-                int Index = i * 2;
-                pbrd->pch[i].power[0].status = tmp[0+Index] & 0x01;
-                pbrd->pch[i].power[0].nwire  = tmp[18] & 0x01;
-            }
-            
-            //获取故障状态
-            offset = POWER_AC3_OUT_ERROR;
-            r = read_reg(h, pbrd->addr, offset, tmp, 18);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            for (i=0; i<pbrd->chs; i++) {
-                int Index = i * 2;
-                pbrd->pch[i].alarm.v_upper = tmp[0+Index] & BIT(0);
-                pbrd->pch[i].alarm.v_lower = tmp[0+Index] & BIT(1);
-                pbrd->pch[i].alarm.c_upper = tmp[0+Index] & BIT(2);
-                pbrd->pch[i].alarm.p_upper = tmp[0+Index] & BIT(3);
-                pbrd->pch[i].alarm.w_upper = tmp[0+Index] & BIT(4);
-            }
-            
-            offset = POWER_AC3_ALARM_MISSING_PH;
-            r = read_reg(h, pbrd->addr, offset, tmp, pbrd->chs);
-            if (r < 0) {
-                LOGE("get_board, addr:%d offset:%d r=%d\n", pbrd->addr, offset, r);
-                return r;
-            }
-            
-            v = 0;
-            for(i = 0; i < 3; i++) {
-                if(tmp[i * 2]>0) {
-                    v |= 1<<i;
-                }
-            }
-            pbrd->ph_loss = v;
+        if(r==0) {
+            threshold_proc(pbrd);
         }
-        break;
-        
-        case AC_MULTI_S_TYPE:
-        case AC_MULTI_B_TYPE:
-        case DC_OUT_TYPE:
-        case DC_IN_TYPE:
-        default:
-        return -1;
     }
+    lock_d_release(h->lck);
     
-    return 0;
+    return r;
 }
 
 
 static void *power_thread(void *arg)
 {
     int r;
-    uint16_t tmp[2]={0};
-    
     thread_handle_t *th=(thread_handle_t*)arg;
     power_handle_t *h=(power_handle_t*)th->arg;;
     
-    power_scan(BRD_MAX);
+    power_scan();
     while(th->quit==0) {
-        
-        //r = read_reg(h, 1, POWER_DC_INFO, tmp, 2);
-        //LOGD("____ read reg %d, %d\n", POWER_DC_INFO, r);
-        //power_get();
-        //
+        board_query(h);
         sleep(1);
     }
     pthread_exit(NULL);
@@ -455,6 +493,8 @@ int power_init(void)
     if(!h->mb) {
         return -1;
     }
+    h->cur_addr = 0;
+    h->brd_max = BRD_MAX;
     thread_start(THREAD_ID_POWER, power_thread, h);
     
     return 0;
@@ -477,11 +517,11 @@ int power_get_ch(int ch, power_ch_t *pch)
     power_handle_t *h=&pwrHandle;
     
     lock_d_hold(h->lck);
-    if(!pch || !h->all.pch || !h->all.chs || !h->all.pch[ch]) {
+    if(!pch || !h->pch || !h->chs || !h->pch[ch]) {
         lock_d_release(h->lck);
         return -1;
     }
-    *pch = *h->all.pch[ch];
+    *pch = *h->pch[ch];
     lock_d_release(h->lck);
     
     return 0;
@@ -493,11 +533,11 @@ int power_get_board(board_data_t *pb)
     power_handle_t *h=&pwrHandle;
     
     lock_d_hold(h->lck);
-    if(!pb || !h->all.pch || !h->all.cnt || !h->all.pbrd[pb->addr]) {
+    if(!pb || !h->pch || !h->cnt || !h->pbrd[pb->addr]) {
         lock_d_release(h->lck);
         return -1;
     }
-    *pb = *h->all.pbrd[pb->addr];
+    *pb = *h->pbrd[pb->addr];
     lock_d_release(h->lck);
     
     return 0;
@@ -509,65 +549,83 @@ int power_set(int ch, power_ch_t *pch)
     power_handle_t *h=&pwrHandle;
     
     lock_d_hold(h->lck);
-    if(!pch || !h->all.pch || !h->all.chs || !h->all.pch[pch->info.ch]) {
+    if(!pch || !h->pch || !h->chs || !h->pch[pch->info.ch]) {
         lock_d_release(h->lck);
         return -1;
     }
-    *h->all.pch[pch->info.ch] = *pch;
+    *h->pch[pch->info.ch] = *pch;
     lock_d_release(h->lck);
     
     return 0;
 }
 
-
-int power_scan(int max_addr)
+static int pch_map(power_handle_t *h, int chs)
 {
-    int r,i,j,idx=0,chs=0;
-    ch_info_t info;
+    int i,j,r,idx=1;
+    board_data_t *pbrd=NULL;
+    uint8_t pwr_type=paras_get()->prod.pwr_type;
+    
+    if(chs>0) {
+        h->chs = 0;
+        h->pch = (power_ch_t**)calloc(1, sizeof(power_ch_t*)*chs);
+        if(h->pch) {
+            h->chs = chs;
+            for(i=1; i<=h->brd_max; i++) {
+                pbrd = h->pbrd[i];
+                if(pbrd) {
+                    for(j=0; j<pbrd->chs; j++) {
+                        h->pch[idx++] = &h->pbrd[i]->pch[j];
+                    }
+                }
+            } 
+        }
+    }
+}
+int power_scan(void)
+{
+    int r,i,j,chs=0;
+    int ch_idx=0,brd_idx=0;
+    board_key_t info;
     power_handle_t *h=&pwrHandle;
+    uint8_t pwr_type=paras_get()->prod.pwr_type;
+    
+    power_clear();
     
     lock_d_hold(h->lck);
-    for(i=1; i<=max_addr; i++) {
-        r = get_info(h, i, &info);
+    h->cur_addr = 0;
+    for(i=1; i<=h->brd_max; i++) {
+        r = get_key(h, i, &h->key[i]);
         LOGD("___ power_scan, addr: %d, result: %d\n", i, r);
-        if(r==0) {
-            h->all.pbrd[i] = (board_data_t*)calloc(1, sizeof(board_data_t));
-            if(h->all.pbrd[i]) {
-                h->all.pbrd[i]->type = info.type;
-                h->all.pbrd[i]->chs  = info.chs;
-                h->all.pbrd[i]->addr = i;
-                h->all.pbrd[i]->pch = (power_ch_t*)calloc(1, sizeof(power_ch_t)*info.chs);
-                if(h->all.pbrd[i]->pch) {
+    }
+    
+    for(i=0; i<h->brd_max; i++) {
+        if(h->key[i].chs>0) {
+            h->pbrd[i] = (board_data_t*)calloc(1, sizeof(board_data_t));
+            if(h->pbrd[i]) {
+                h->pbrd[i]->type = info.type;
+                h->pbrd[i]->chs  = info.chs;
+                h->pbrd[i]->addr = i;
+                h->pbrd[i]->ch0 = ch_idx;
+                h->pbrd[i]->pch = (power_ch_t*)calloc(1, sizeof(power_ch_t)*info.chs);
+                if(h->pbrd[i]->pch) {
                     for(j=0; j<info.chs; j++) {
-                        h->all.pbrd[i]->pch[j].info.addr = i;
-                        h->all.pbrd[i]->pch[j].info.ch  = idx;      //序号程序从0开始
-                        h->all.pbrd[i]->pch[j].info.sch = j;        //序号从0开始
-                        h->all.pbrd[i]->pch[j].info.pid = i;
-                        h->all.pbrd[i]->pch[j].info.addr = i;
+                        h->pbrd[i]->pch[j].info.addr = i;
+                        h->pbrd[i]->pch[j].info.ch  = ch_idx;       //序号程序从0开始
+                        h->pbrd[i]->pch[j].info.sch = j;            //序号从0开始
                         
-                        idx++;
+                        if(info.type==TREE_AC_TYPE) {
+                            h->pbrd[i]->pch[j].info.pid = i;
+                            
+                        }
+                        h->pbrd[i]->pch[j].info.addr = i;
+                        ch_idx++;
                     }
                 }
+                brd_idx++;
             }
             chs += info.chs;
         }
     }
-    
-    if(chs>0) {
-        idx = 0;
-        h->all.chs = 0;
-        h->all.pch = (power_ch_t**)calloc(1, sizeof(power_ch_t*)*chs);
-        if(h->all.pch) {
-            h->all.chs = chs;
-            for(i=1; i<=max_addr; i++) {
-                board_data_t *pbrd=h->all.pbrd[i];
-                for(j=0; j<pbrd->chs; j++) {
-                    h->all.pch[idx++] = &h->all.pbrd[i]->pch[j];
-                }
-            } 
-        }
-    }
-    
     lock_d_release(h->lck);
     
     return 0;
@@ -580,20 +638,21 @@ int power_clear(void)
     power_handle_t *h=&pwrHandle;
   
     lock_d_hold(h->lck);
-    for(i=0; i<BRD_MAX; i++) {
-        if(h->all.pbrd[i]) {
-            for(j=0; j<h->all.pbrd[i]->chs; j++) {
-                if(h->all.pbrd[i]->pch) {
-                    free(h->all.pbrd[i]->pch);
-                    h->all.pbrd[i]->pch = NULL;
+    for(i=0; i<=h->brd_max; i++) {
+        if(h->pbrd[i]) {
+            for(j=0; j<h->pbrd[i]->chs; j++) {
+                if(h->pbrd[i]->pch) {
+                    free(h->pbrd[i]->pch);
+                    h->pbrd[i]->pch = NULL;
                 }
-                h->all.pbrd[i]->chs = 0;
+                h->pbrd[i]->chs = 0;
             }
-            free(h->all.pbrd[i]);
-            h->all.pbrd[i] = NULL;
+            free(h->pbrd[i]);
+            h->pbrd[i] = NULL;
         }
-        h->all.cnt = 0;
     }
+    memset(h->key, 0, sizeof(h->key));
+    h->cnt = 0;
     lock_d_release(h->lck);
     
     return 0;
@@ -607,10 +666,10 @@ int power_reset(int addr)
     power_handle_t *h=&pwrHandle;
     board_data_t *pb=NULL;
     
-    if(addr>BRD_MAX) {
+    if(addr>h->brd_max) {
         return -1;
     }
-    pb = h->all.pbrd[addr];
+    pb = h->pbrd[addr];
     if(!pb) {
         return -1;
     }

+ 1 - 1
f407/applications/power.h

@@ -153,7 +153,7 @@ int power_init(void);
 int power_deinit(void);
 int power_clear(void);
 
-int power_scan(int max_addr);
+int power_scan(void);
 int power_get_ch(int ch, power_ch_t *pch);
 int power_get_board(board_data_t *pb);
 

+ 1 - 4
f407/applications/ui/lcd.c

@@ -151,10 +151,7 @@ static void ssd1309_refresh(lcd_handle_t *h)
 	   lcd_write_reg(h,0x10);   			//设置高列起始地址
 
        gpio_set(DC_GPIO, 1);
-       offset = i*128;
-	   for(n=0;n<128;n++) {
-          lcd_hw_write(h, &h->buf[offset+n], 1);
-	   }
+       lcd_hw_write(h, &h->buf[i*h->width], h->width);
   	}
 }
 static int lcd_hw_deinit(lcd_handle_t *h)

+ 75 - 0
f407/applications/ui/ssd1309.c

@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include "gpio.h"
+#include "lcd.h"
+#include "log.h"
+
+
+void ssd1309_on(lcd_handle_t *h, int flag)
+{
+    if(flag) {
+        lcd_write_reg(h,0x8D);
+	    lcd_write_reg(h,0x14);
+	    lcd_write_reg(h,0xAF);
+    }
+    else {
+        lcd_write_reg(h,0x8D);
+	    lcd_write_reg(h,0x10);
+	    lcd_write_reg(h,0xAE);
+    }
+    return 0;
+}
+
+int ssd1309_init(lcd_handle_t *h)
+{
+    ssd1309_reset();
+
+    lcd_write_reg(h,0xFD);
+	lcd_write_reg(h,0x12);
+	lcd_write_reg(h,0xAE);//--turn off oled panel
+	lcd_write_reg(h,0xd5);//--set display clock divide ratio/oscillator frequency
+	lcd_write_reg(h,0xA0);
+	lcd_write_reg(h,0xA8);//--set multiplex ratio(1 to 64)
+	lcd_write_reg(h,0x3f);//--1/64 duty
+	lcd_write_reg(h,0xD3);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
+	lcd_write_reg(h,0x00);//-not offset
+	lcd_write_reg(h,0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
+	lcd_write_reg(h,0xA1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
+	lcd_write_reg(h,0xC8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
+	lcd_write_reg(h,0xDA);//--set com pins hardware configuration
+	lcd_write_reg(h,0x12);
+	lcd_write_reg(h,0x81);//--set contrast control register
+	lcd_write_reg(h,0x7F);// Set SEG Output Current Brightness
+	lcd_write_reg(h,0xD9);//--set pre-charge period
+	lcd_write_reg(h,0x82);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
+	lcd_write_reg(h,0xDB);//--set vcomh
+	lcd_write_reg(h,0x34);//Set VCOM Deselect Level
+	lcd_write_reg(h,0xA4);// Disable Entire Display On (0xa4/0xa5)
+	lcd_write_reg(h,0xA6);// Disable Inverse Display On (0xa6/a7)
+
+    ssd1309_refresh(h);
+    ssd1309_on(h,1);
+	
+	return 0;
+}
+
+int ssd1309_refresh(lcd_handle_t *h)
+{
+	int i,n,offset;
+    
+	for(i=0;i<8;i++) {
+	   lcd_write_reg(h,0xb0+i); 			//设置行起始地址
+	   lcd_write_reg(h,0x00);   			//设置低列起始地址
+	   lcd_write_reg(h,0x10);   			//设置高列起始地址
+
+       gpio_set(DC_GPIO, 1);
+       lcd_hw_write(h, &h->buf[i*h->width], h->width);
+  	}
+}
+
+
+
+

+ 422 - 0
f407/applications/ui/st7789.c

@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2023-06-10     Vandoul       First version
+ */
+
+#include "rtthread.h"
+#include "lcd_st7789.h"
+
+#define DBG_TAG "st7789"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef PKG_USING_ST7789
+
+#define LCD_CMD_COL_ADDR_SET                0x2A
+#define LCD_CMD_ROW_ADDR_SET                0x2B
+#define LCD_CMD_MEMORY_WRITE                0x2C
+/**
+ * MADCTL(36H):
+ * +---------------------------------------+
+ * | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
+ * | MY | MX | MV | ML | RGB| MH |  - |  - |
+ * +---------------------------------------+
+ * [3] 0=RGB,1=BGR
+*/
+#define LCD_CMD_MEMORY_DATA_ACCESS_CTRL     0x36
+/**
+ * COLMOD(3AH):
+ * +---------------------------------------+
+ * | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
+ * |  0 | D6 | D5 | D4 |  0 | D2 | D1 | D0 |
+ * +---------------------------------------+
+ * [6:4] RGB interface Color format:
+ *      101=65K RGB
+ *      110=262K RGB
+ * [2:0] Control interface color format:
+ *      011=12bit/pixel
+ *      101=16bit/pixel
+ *      110=18bit/pixel
+ *      111=16M truncated
+*/
+#define LCD_CMD_INTERFACE_PIXEL_FORMAT      0x3A
+
+
+typedef struct
+{
+    struct rt_device parent;
+    uint16_t width;   /* LCD width */
+    uint16_t height;  /* LCD high */
+    uint32_t id;      /* LCD ID */
+    uint8_t dir;      /* 0:Vertical | 1:Vertical */
+} _lcd_dev;
+
+/* LCD param */
+_lcd_dev lcddev;
+static struct rt_spi_device *lcd_dev;
+static uint16_t frame_buf[LCD_H][LCD_W];
+static void LCD_RESET(void)
+{
+    LCD_RES_CLR;
+    DELAY(100);
+    LCD_RES_SET;
+    DELAY(100);
+}
+
+static void LCD_WR_REG(uint8_t reg)
+{
+    LCD_DC_CLR;
+    rt_spi_send(lcd_dev, &reg, 1);
+    LCD_DC_SET;
+}
+
+static void LCD_WR_DATA(uint8_t data)
+{
+    LCD_DC_SET;
+    rt_spi_send(lcd_dev, &data, 1);
+}
+
+static void LCD_ReadData(uint8_t *data, uint16_t length)
+{
+    LCD_DC_SET;
+    rt_spi_transfer(lcd_dev, RT_NULL, &data, length);
+}
+
+static void LCD_WriteReg(uint8_t reg, uint16_t regdata)
+{
+    LCD_WR_REG(reg);
+    LCD_WR_DATA(regdata);
+}
+
+static void LCD_WriteRAM_Prepare(void)
+{
+    LCD_WR_REG(LCD_CMD_MEMORY_WRITE);
+}
+
+static void LCD_WriteData_16Bit(uint16_t Data)
+{
+    uint8_t buf[2];
+    LCD_DC_SET;
+    buf[0] = Data >> 8;
+    buf[1] = Data & 0xff;
+    rt_spi_send(lcd_dev, buf, 2);
+}
+
+void LCD_direction(uint8_t direction)
+{
+    switch (direction)
+    {
+    case 0:
+        lcddev.width = LCD_W;
+        lcddev.height = LCD_H;
+        LCD_WriteReg(LCD_CMD_MEMORY_DATA_ACCESS_CTRL, (0 << 3) | (0 << 5) | (0 << 6) | (0 << 7)); /* BGR==0,MV==0,MX==0,MY==0 */
+        break;
+    case 1:
+        lcddev.width = LCD_H;
+        lcddev.height = LCD_W;
+        LCD_WriteReg(LCD_CMD_MEMORY_DATA_ACCESS_CTRL, (0 << 3) | (1 << 5) | (1 << 6) | (0 << 7)); /* BGR==0,MV==1,MX==0,MY==1 */
+        break;
+    case 2:
+        lcddev.width = LCD_W;
+        lcddev.height = LCD_H;
+        LCD_WriteReg(LCD_CMD_MEMORY_DATA_ACCESS_CTRL, (0 << 3) | (0 << 5) | (1 << 6) | (1 << 7)); /* BGR==0,MV==0,MX==1,MY==1 */
+        break;
+    case 3:
+        lcddev.width = LCD_H;
+        lcddev.height = LCD_W;
+        LCD_WriteReg(LCD_CMD_MEMORY_DATA_ACCESS_CTRL, (0 << 3) | (1 << 5) | (0 << 6) | (1 << 7)); /* BGR==0,MV==1,MX==0,MY==1 */
+        break;
+    default:
+        break;
+    }
+}
+
+void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
+{
+    LCD_WR_REG(LCD_CMD_COL_ADDR_SET);
+    LCD_WR_DATA(xStar >> 8);
+    LCD_WR_DATA(0x00FF & xStar);
+    LCD_WR_DATA(xEnd >> 8);
+    LCD_WR_DATA(0x00FF & xEnd);
+
+    LCD_WR_REG(LCD_CMD_ROW_ADDR_SET);
+    LCD_WR_DATA(yStar >> 8);
+    LCD_WR_DATA(0x00FF & yStar);
+    LCD_WR_DATA(yEnd >> 8);
+    LCD_WR_DATA(0x00FF & yEnd);
+
+    LCD_WriteRAM_Prepare();
+}
+
+void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
+{
+    LCD_SetWindows(Xpos, Ypos, Xpos, Ypos);
+}
+
+void LCD_Clear(uint16_t Color)
+{
+    unsigned int i, m;
+
+    LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
+
+    LCD_DC_SET;
+    for (i = 0; i < lcddev.height; i++)
+    {
+        for (m = 0; m < lcddev.width; m++)
+        {
+            frame_buf[i][m] = Color;
+        }
+        for (m = 0; m < lcddev.width;)
+        {
+            m += 40;
+            rt_spi_send(lcd_dev, (uint8_t *)&frame_buf[i][m], 80);
+        }
+    }
+}
+
+void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
+{
+    uint16_t i, j;
+    LCD_SetWindows(xsta, ysta, xend - 1, yend - 1);
+    for (i = ysta; i < yend; i++)
+    {
+        for (j = xsta; j < xend; j++)
+        {
+            frame_buf[i][j] = color;
+            LCD_WriteData_16Bit(color);
+        }
+    }
+}
+
+void LCD_Sync_fb(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+    uint16_t i, j;
+    LCD_SetWindows(x, y, x + w - 1, y + h - 1);
+    LCD_DC_SET;
+    for (i = 0; i < h; i++)
+    {
+        rt_spi_send(lcd_dev, (uint8_t *)&frame_buf[y+i][x], w * 2);
+    }
+}
+
+void lcd_fill_array_spi(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t *Image)
+{
+    rt_uint32_t size = 0;
+    uint16_t *pImage = Image;
+
+    size = (Xend - Xstart + 1) * (Yend - Ystart + 1) * 2;/*16bit*/
+    LCD_SetWindows(Xstart, Ystart, Xend, Yend);
+    LCD_DC_SET;
+
+    for(int i=0; i<(Yend - Ystart); i++)
+    {
+        for(int j=0; j<(Xend - Xstart); j++)
+        {
+            frame_buf[i + Ystart][j + Xstart] = *pImage++;
+        }
+    }
+    rt_spi_send(lcd_dev, Image, size);
+}
+
+static void _st7789_init(void)
+{
+    LCD_WR_REG(LCD_CMD_MEMORY_DATA_ACCESS_CTRL);
+    LCD_WR_DATA(0x00);
+
+    LCD_WR_REG(LCD_CMD_INTERFACE_PIXEL_FORMAT);
+    LCD_WR_DATA(0X05); //03=RGB444,05=RGB565,06=RGB666
+
+    LCD_WR_REG(0xB2); //Porch Setting
+    LCD_WR_DATA(0x0C);
+    LCD_WR_DATA(0x0C);
+    LCD_WR_DATA(0X00);
+    LCD_WR_DATA(0X33);
+    LCD_WR_DATA(0X33);
+
+    LCD_WR_REG(0xB7); //Gate Control
+    LCD_WR_DATA(0x46);
+
+    LCD_WR_REG(0xBB); //VCOM Setting
+    LCD_WR_DATA(0x1B);
+
+    LCD_WR_REG(0xC0); //LCM Control
+    LCD_WR_DATA(0x2C);
+
+    LCD_WR_REG(0xC2); //VDV and VRH Command Enable
+    LCD_WR_DATA(0x01);
+
+    LCD_WR_REG(0xC3); //VRH set
+    LCD_WR_DATA(0x0F);
+
+    LCD_WR_REG(0xC4); //VDV set
+    LCD_WR_DATA(0x20);
+
+    LCD_WR_REG(0xC6); //Frame Rate Control
+    LCD_WR_DATA(0x0F);
+
+    LCD_WR_REG(0xD0); //Power Control 1
+    LCD_WR_DATA(0xA4);
+    LCD_WR_DATA(0xA1);
+
+    LCD_WR_REG(0xD6);
+    LCD_WR_DATA(0xA1);
+
+    LCD_WR_REG(0xE0);   /* set Positive Voltage Gamma */
+    LCD_WR_DATA(0xF0);
+    LCD_WR_DATA(0x00);
+    LCD_WR_DATA(0x06);
+    LCD_WR_DATA(0x04);
+    LCD_WR_DATA(0x05);
+    LCD_WR_DATA(0x05);
+    LCD_WR_DATA(0x31);
+    LCD_WR_DATA(0x44);
+    LCD_WR_DATA(0x48);
+    LCD_WR_DATA(0x36);
+    LCD_WR_DATA(0x12);
+    LCD_WR_DATA(0x12);
+    LCD_WR_DATA(0x2B);
+    LCD_WR_DATA(0x34);
+
+    LCD_WR_REG(0xE1);   /* set Negative Voltage Gamma */
+    LCD_WR_DATA(0XF0);
+    LCD_WR_DATA(0X0B);
+    LCD_WR_DATA(0X0F);
+    LCD_WR_DATA(0X0F);
+    LCD_WR_DATA(0X0D);
+    LCD_WR_DATA(0X26);
+    LCD_WR_DATA(0X31);
+    LCD_WR_DATA(0X43);
+    LCD_WR_DATA(0X47);
+    LCD_WR_DATA(0X38);
+    LCD_WR_DATA(0X14);
+    LCD_WR_DATA(0X14);
+    LCD_WR_DATA(0X2C);
+    LCD_WR_DATA(0X32);
+
+    LCD_WR_REG(0x21); // Dispaly Inversion On
+
+    LCD_WR_REG(0x29); // Display On
+
+    LCD_WR_REG(LCD_CMD_MEMORY_WRITE); // Memory Write
+}
+
+static void Lcd_pin_init(void)
+{
+    rt_pin_mode(PKG_ST_7789_DC_PIN, PIN_MODE_OUTPUT);
+    rt_pin_mode(PKG_ST_7789_RES_PIN, PIN_MODE_OUTPUT);
+    rt_pin_mode(PKG_ST_7789_BLK_PIN, PIN_MODE_OUTPUT);
+}
+
+static void LCD_Init(void)
+{
+    Lcd_pin_init();
+
+    LCD_RESET();        /* LCD Hardware Reset */
+    DELAY(120);         /* Delay 120ms */
+    LCD_WR_REG(0x11);   /* Sleep out */
+    DELAY(120);         /* Delay 120ms */
+    _st7789_init();    /* IlI9341 init */
+    LCD_BLK_CLR;        /* Open Backlight */
+
+    LCD_direction(USE_DIRECTION);
+}
+
+rt_err_t spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
+{
+    RT_ASSERT(bus_name != RT_NULL);
+    RT_ASSERT(device_name != RT_NULL);
+
+    rt_err_t result = RT_EOK;
+    struct rt_spi_device *spi_device;
+
+    /* attach the device to spi bus*/
+    spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
+    RT_ASSERT(spi_device != RT_NULL);
+
+    result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
+    if (RT_EOK != result)
+    {
+        LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
+    }
+    else
+    {
+        LOG_I("%s attach to %s done", device_name, bus_name);
+    }
+
+    return result;
+}
+
+rt_err_t spi_lcd_init(uint32_t freq)
+{
+    rt_err_t res = RT_EOK;
+
+    spi_device_attach(PKG_ST_7789_SPI_BUS_NAME, PKG_ST_7789_SPI_DEVICE_NAME, PKG_ST_7789_CS_PIN);
+    lcd_dev = (struct rt_spi_device *)rt_device_find(PKG_ST_7789_SPI_DEVICE_NAME);
+    if (lcd_dev != RT_NULL)
+    {
+        struct rt_spi_configuration spi_config;
+        spi_config.data_width = 8;
+        spi_config.max_hz = freq * 1000 * 1000;
+        spi_config.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
+        rt_spi_configure(lcd_dev, &spi_config);
+    }
+    else
+    {
+        res = -RT_ERROR;
+    }
+
+    LCD_Init();
+
+    return res;
+}
+#if 0
+static void lcd_ops_set_pixel (const char *pixel, int x, int y)
+{
+}
+static void lcd_ops_get_pixel (char *pixel, int x, int y)
+{
+}
+static void lcd_ops_draw_hline(const char *pixel, int x1, int x2, int y)
+{
+}
+static void lcd_ops_draw_vline(const char *pixel, int x, int y1, int y2)
+{
+}
+#endif
+static void lcd_ops_blit_line(const char *pixel, int x, int y, rt_size_t size)
+{
+    LCD_SetWindows(x, y, x + size, y);
+    rt_spi_send(lcd_dev, pixel, size * 2);
+}
+struct rt_device_graphic_ops lcd_graphic_ops =
+{
+    .set_pixel  = RT_NULL,//lcd_ops_set_pixel ,
+    .get_pixel  = RT_NULL,//lcd_ops_get_pixel ,
+    .draw_hline = RT_NULL,//lcd_ops_draw_hline,
+    .draw_vline = RT_NULL,//lcd_ops_draw_vline,
+    .blit_line  = lcd_ops_blit_line ,
+};
+
+static int lcd_dev_init(void)
+{
+    #ifdef RT_USING_DEVICE_OPS
+    lcddev.parent.ops = &lcd_dev_ops;
+    #else
+    lcddev.parent.init    = lcd_dev_ops_init   ;
+    lcddev.parent.open    = lcd_dev_ops_open   ;
+    lcddev.parent.close   = lcd_dev_ops_close  ;
+    lcddev.parent.read    = lcd_dev_ops_read   ;
+    lcddev.parent.write   = lcd_dev_ops_write  ;
+    lcddev.parent.control = lcd_dev_ops_control;
+    #endif
+    lcddev.parent.type = RT_Device_Class_Graphic;
+    lcddev.parent.user_data = &lcd_graphic_ops;
+    rt_device_register(&lcddev.parent, "lcd", RT_DEVICE_FLAG_RDWR);
+    return RT_EOK;
+}
+