hacking 麦步手表之(3)制作一个英文表盘xzy-reborn

前不久,出了一件怪事,不知道是太阳风暴,还是恰逢农历闰六月的,

还是其他原因引起,

我的手表开始不断死机重启.

正想是不是联系售后寄回去时,

我发现了只要切换别的表盘就一切正常了,

再切换回"超清时钟"表盘有就立出现故障,

无奈只好忍痛割爱.

之后发现官方也把这个表盘下架了.


一时间再也找不到代替的时钟表盘.于是只好自己动手丰衣足食,自己做一个.

第一步:找素材

上官方淘宝评论找"高清时钟"的表盘图片,为了凑齐0~9的图片,可是费了九牛二虎之力


第二步,依葫芦画瓢


第三步:写代码

appinfo.json

{
  "uuid": "e06ee4971ac29fd1b94f99cc9e8f93e5",
  "name": "reborn",
  "icon": "",
  "version": "1.0.9",
  "watchface": "true",
  "resources": [
	  {
        "type": "bmp",
        "name": "BMP_BG",
        "file": "bg.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_0",
        "file": "0.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_1",
        "file": "1.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_2",
        "file": "2.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_3",
        "file": "3.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_4",
        "file": "4.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_5",
        "file": "5.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_6",
        "file": "6.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_7",
        "file": "7.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_8",
        "file": "8.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_9",
        "file": "9.bmp"
      },
	  {
        "type": "bmp",
        "name": "BMP_COLON",
        "file": "COLON.bmp"
      }
      ]
}

主程序xyz_reborn.c

/*
 * =====================================================================================
 *    WatchFaceName:   xyz-reborn
 *    Description: 
 *    Author:  wisepragma
 *    Created: August 4,2017
 *    HomePage:http://blog.csdn.net/wisepragma
 * =====================================================================================
 */  
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "maibu_sdk.h"
#include "maibu_res.h"

 int32_t app_window_stack_push(Window *window);
 int8_t maibu_get_battery_percent(int8_t *percent);
 Window * app_window_stack_get_window_by_id(int32_t id);
 void app_window_update(Window *window);



static void fillGRect(GRect *grc,uint8_t x,uint8_t y,uint8_t h,uint8_t w)
{
          grc->origin.x=x;
          grc->origin.y=y;
          grc->size.w=w;
          grc->size.h=h;
}
static const uint16_t N_MIN_HIDE_SEC=3;
static const char ORGIN_X=0,ORGIN_Y=33;//大数字起始位置
static GSize WATCH_NUM_SIZE={0,0};//大数字的高与宽,从图片资源上获取
static uint32_t    half_sec_cnt = 0;
static struct date_time last_time;
static struct TIME_NUM
{
       uint8_t     value;
       int8_t      lyid;
       GRect       rc;
}T_num[4];
               
static  P_Window   p_win=NULL;
//bugfixed: layer id equal 0,is legal,changed initial value 0 to -1
static int32_t      win_id =-1;
static int32_t      timer_id =-1;

static int8_t       lyid_battery = -1;
static int8_t       lyid_engtime1 = -1;
static int8_t       lyid_engtime2 = -1;
static int8_t       lyid_weekday = -1;
static int8_t       lyid_mondayyear = -1;
static int8_t       lyid_sec = -1;

static const uint16_t         tnum_bmp[10] = {BMP_0, BMP_1, BMP_2, BMP_3, BMP_4, BMP_5, BMP_6, BMP_7, BMP_8, BMP_9};
static const char               wday[7][10] ={ "Sunday","Monday","Tuesday","Wednesday","Thursday", "Friday", "Saturday" }; 
static const char               month[12][10] ={"January","February","March","April","May","June","July","August","September","October","November","December"};

static const char     s_num[][10] = {    "twelve",
                                                       "one","two","three","four","five","six","seven","eight","nine",     
                                                       "ten",   
                                                       "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen",    
                                                       "twenty"   };
static const char     s_decade[][8] =  {  "","","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety", };
                                                           
                                                               
                                                           
static char *gen_min_str(uint8_t  num,char *buf)
{
             if(num<=20)  sprintf(buf,"%s",s_num[num]);
             else
             {         
                    sprintf(buf,"%s",s_decade[num/10]);
                    if((num%10)!=0)  sprintf(buf,"%s-%s",s_decade[num/10],s_num[num%10]);
                    else  sprintf(buf,"%s",s_decade[num/10]);
             }
             return buf;
}

static char *gen_time_str(uint8_t hour,uint8_t  min,char *recvbuf,char *recvbuf2)//recvbuf at least 32
{
     char min_str[32];
     char *prefix,*stuffix,*past_to,*am_pm;  
     if(hour>=24   || min>59 ) return 0;
     if(hour>=12)  am_pm="p.m.";  else am_pm="a.m.";
     if(min==0)
     {
          prefix=(char*)s_num[hour%12]; //%12变成12小时制
          past_to="o'clock" ;
          // if(hour==-1) { stuffix=" a.m.";am_pm=",midnight";}//显示不了那么多字只好注释掉
          // else if(hour==12) { stuffix="p.m.";am_pm=",noon";}
          // else 
           stuffix=""; 
     }
     else if(min==30){  prefix="half"; past_to="past" ;stuffix=(char*)s_num[hour%12];}
     else if(min==15){  prefix="a quarter"; past_to="past";stuffix=(char*)s_num[hour%12];}
     else if(min==45) {  prefix="a quarter"; past_to="to";stuffix=(char*)s_num[(hour+1)%12];}
     else if(0<min &&  min<30) 
     { 
          prefix=gen_min_str(min,min_str);
          past_to="past";
          stuffix=(char*)s_num[hour%12];
     }
     else   if(min>30) 
      {
          prefix=gen_min_str(60-min,min_str);
          past_to="to";
          stuffix=(char*)s_num[(hour+1)%12];
      }
      sprintf(recvbuf,"%s ", prefix);
      sprintf(recvbuf2,"%s %s %s",past_to, stuffix,am_pm);
      recvbuf[0]-=('a'-'A');//首字母大写
      return recvbuf;
}



static int8_t  create_txt_layer(Window *pwin, char *txt,uint8_t font_type,int16_t x,int16_t y,uint8_t h,uint8_t w,enum GColor ecolor,enum GAlign align)//return layer id
{
     GRect frame_hm;
     fillGRect( &frame_hm,x,y,h,w );
     LayerText alt_hm = {txt, frame_hm, align, font_type, 0};
     P_Layer layer = app_layer_create_text(&alt_hm);
     int8_t id=-1;
     if(layer != NULL)
     {
          app_layer_set_bg_color(layer, ecolor); 
          id = app_window_add_layer(pwin, layer);
     }
     return id;
}
static int8_t create_bmp_layer(Window *pwin, uint32_t bmpID,int16_t x,int16_t y,uint8_t h,uint8_t w/*,enum GColor ecolor*/)
{
     int8_t lyid=-1;
     GRect frame_bg;
     GBitmap bitmap_bg;//height,width
     res_get_user_bitmap(bmpID, &bitmap_bg);
     fillGRect( &frame_bg,x,y,h,w );

     LayerBitmap lb_bg = {bitmap_bg, frame_bg, GAlignLeft}; 
     P_Layer layer_bitmap_bg = app_layer_create_bitmap(&lb_bg);
     //app_layer_set_bg_color(layer_bitmap_bg, ecolor); 
     if(layer_bitmap_bg != NULL)
     {
          lyid=app_window_add_layer(pwin, layer_bitmap_bg);
     }
     return lyid;
}
 
//==========English time ======================
 static void update_english_layer(struct date_time *datetime)
 {
        char txt_buf[32],txt_buf2[32];
        sprintf(txt_buf,"%s", gen_time_str(datetime->hour,datetime->min,txt_buf,txt_buf2));          
        if( lyid_engtime1==-1 || lyid_engtime2==-1)
        {
                    lyid_engtime1=  create_txt_layer(p_win, txt_buf,U_ASCII_ARIAL_16,0, 92,  16,  127,GColorBlack,GAlignTopLeft);
                    lyid_engtime2=   create_txt_layer(p_win, txt_buf2,U_ASCII_ARIAL_16,0, 110,  16,  127,GColorBlack,GAlignTopRight); 
        }
        else
        {
                    P_Layer p_layer= app_window_get_layer_by_id(p_win, lyid_engtime1);     
                    app_layer_set_text_text(p_layer, txt_buf);
                    p_layer= app_window_get_layer_by_id(p_win, lyid_engtime2);     
                    app_layer_set_text_text(p_layer, txt_buf2);     
         }
 }
//================================
static void update_mondayyear_layer(struct date_time *datetime)
{
          char  txt_buf[40],*str_stuffix;
          //凡个位为1,2,3 除11,12,13区别对待
          switch(  datetime->mday%10  )//%10取0~9数,%100取0~99
          {
               case 1:  str_stuffix="st";    if(datetime->mday%100==11)   str_stuffix="th";  break;
               case 2:  str_stuffix="nd";   if(datetime->mday%100==12)   str_stuffix="th";  break;
               case 3:  str_stuffix="rd";    if(datetime->mday%100==13)   str_stuffix="th";  break;
               default:
                         str_stuffix="th";
          }
          sprintf(txt_buf,"%s  %d%s,%d",  month[datetime->mon-1], datetime->mday,str_stuffix,datetime->year);
          if(  lyid_mondayyear ==-1)
          {
               lyid_mondayyear =create_txt_layer(p_win, txt_buf,U_ASCII_ARIAL_12,0, 0,  32,  127,GColorBlack,GAlignTopLeft);
          }   
          else
          {
               P_Layer p_layer= app_window_get_layer_by_id(p_win, lyid_mondayyear);     
               app_layer_set_text_text(p_layer, txt_buf);
          }
}     
//=========hour min======================
static void update_hour_min_layer(struct date_time *datetime)
{
         GBitmap        bitmap;
          T_num[0].value= datetime->hour/10;
          T_num[1].value= datetime->hour%10;
          T_num[2].value= datetime->min/10;
          T_num[3].value= datetime->min%10;
                       
         if(T_num[0].lyid==-1)
         {        

               fillGRect( &T_num[0].rc,  ORGIN_X,  ORGIN_Y,       WATCH_NUM_SIZE.h,  WATCH_NUM_SIZE.w  );
               fillGRect( &T_num[1].rc,  WATCH_NUM_SIZE.w,  ORGIN_Y,      WATCH_NUM_SIZE.h,  WATCH_NUM_SIZE.w  ); 
               fillGRect( &T_num[2].rc,  16+2*WATCH_NUM_SIZE.w,  ORGIN_Y,    WATCH_NUM_SIZE.h,  WATCH_NUM_SIZE.w ); 
               fillGRect( &T_num[3].rc,  16+3*WATCH_NUM_SIZE.w,  ORGIN_Y,     WATCH_NUM_SIZE.h,  WATCH_NUM_SIZE.w  ); 
          }
          for(int pos=0;pos<4;pos++)
          {

               if(T_num[pos].lyid==-1)
               {
                         T_num[pos].lyid =create_bmp_layer( p_win, tnum_bmp[ T_num[pos].value],  T_num[pos].rc.origin.x,  T_num[pos].rc.origin.y,T_num[pos].rc.size.h, T_num[pos].rc.size.w );
               }
               else
               {
                          P_Layer      p_layer = app_window_get_layer_by_id(p_win, T_num[pos].lyid);             
                         if (p_layer != NULL)
                         {
                              res_get_user_bitmap(tnum_bmp[  T_num[pos].value  ], &bitmap);
                              app_layer_set_bitmap_bitmap(p_layer, &bitmap);
                         }                    
               }
        }
}
//=========weekday======================
 static void update_wday_layer(struct date_time *datetime)
     {     
          char txt_buf[32];
          sprintf(txt_buf, "%s", wday[datetime->wday]);
          if(lyid_weekday==-1)
          {
                  lyid_weekday =      create_txt_layer(p_win, txt_buf,U_ASCII_ARIAL_16,0, 14,  32,  127,GColorBlack,GAlignTopLeft);
          }
          else
          {
                 P_Layer p_layer= app_window_get_layer_by_id(p_win, lyid_weekday);     
                 app_layer_set_text_text(p_layer, txt_buf);         
          }
     }
//=========battery======================
static   void update_battery_layer()
     {
          //电量 
          int8_t percent=0;
          char txt_buf[5];
          maibu_get_battery_percent(&percent);
          sprintf(txt_buf, "%d%%", percent);
          if(lyid_battery==-1)
          {
               lyid_battery = create_txt_layer(p_win, txt_buf,U_ASCII_ARIAL_16, 127-41, 14, 32,41,GColorBlack,GAlignTopRight);
          }      
          else
          {
               P_Layer  p_layer= app_window_get_layer_by_id(p_win, lyid_battery);     
               app_layer_set_text_text(p_layer, txt_buf);
          }
     }

//========second========================
static void update_second_layer(uint8_t second)
{
          char txt_buf[5];
          if(half_sec_cnt!=0) sprintf(txt_buf, "%02d", second);//date_time_t是date_time的指针
          else  txt_buf[0]='\0';         

          if(lyid_sec==-1)
          {
                    lyid_sec=create_txt_layer(p_win, txt_buf,U_ASCII_ARIAL_14,  2*WATCH_NUM_SIZE.w+1,   ORGIN_Y+22,  30,  30,GColorWhite,GAlignTopLeft);
          }
          else
          {
                    P_Layer    p_layer= app_window_get_layer_by_id(p_win, lyid_sec);  
                    if (p_layer == NULL)  return;    
                    app_layer_set_text_text(p_layer, txt_buf);
          }
}
//================================
static void sec_callback(date_time_t tick_time, uint32_t millis,void *context)
{
          half_sec_cnt++;   //500ms刷新一次,避免秒慢于分钟更新
          if(half_sec_cnt>=N_MIN_HIDE_SEC*60*2)//几钟后停止显示秒
          {
               app_service_timer_unsubscribe(timer_id);
               half_sec_cnt=0;
          }
         P_Window      p_win =app_window_stack_get_window_by_id(win_id);//(P_Window)context;
          if (p_win == NULL)  return;
          update_second_layer( tick_time->sec );
          app_window_update(p_win);
}
 static void on_back_key() 
 {
	P_Window p_win = app_window_stack_get_window_by_id(win_id);
	if(p_win != NULL)
	{
         if(half_sec_cnt==0)
         {
              timer_id=app_window_timer_subscribe(p_win, 500, sec_callback, 0);
         }
         else
         {
               app_service_timer_unsubscribe(timer_id);
               half_sec_cnt=0;                        
               struct date_time datetime;
               app_service_get_datetime(&datetime);
               update_second_layer( datetime.sec );
               app_window_update(p_win);
         }
	}
	
}

static void time_change_callback(enum SysEventType type, void *context)
{
     if (type == SysEventTypeTimeChange)
     {
          P_Window      p_win =(P_Window)app_window_stack_get_window_by_id(win_id);
          if (p_win == NULL)  return;
          struct date_time datetime;
          app_service_get_datetime(&datetime);
          //时分
          update_hour_min_layer( &datetime );
          //English Time
          update_english_layer(&datetime);        
          //电量 
          update_battery_layer();     
          if(datetime.year !=last_time.year || datetime.mon!=last_time.mon || datetime.mday!=last_time.mday)
          {
               //星期几
               update_wday_layer( &datetime );
               //月,日年
               update_mondayyear_layer( &datetime );
               
               last_time.year = datetime.year;
               last_time.mon = datetime.mon;
               last_time.mday = datetime.mday;             
          }
          app_window_update(p_win);    
     }
}
//---------------main-----------------------------------------------------------------------
int main()
{
          #ifdef USE_SIMULATOR
               simulator_init();
          #endif
          //....................切换表盘时,资源已销毁,要重新创建layer,否则将不能正常显示.............................................................
          win_id =-1;
          half_sec_cnt =0;//bugfixed -1
          timer_id =-1;

          lyid_battery =-1;
          lyid_engtime1 =-1;
          lyid_engtime2 =-1;
          lyid_weekday =-1;
          lyid_mondayyear =-1;
          lyid_sec =-1;
          memset(T_num,-1,sizeof(T_num));
          //.........................................................................................................................
           
           
          p_win = app_window_create();
          if (p_win == NULL) return 0;
          
          struct date_time datetime;
          app_service_get_datetime(&datetime);
          
          GBitmap bitmap; 
          res_get_user_bitmap(*tnum_bmp, &bitmap);//BMP_ID中取得宽高信息
          WATCH_NUM_SIZE.h=bitmap.height;
          WATCH_NUM_SIZE.w=bitmap.width;
          //背景.放最前面-once
          res_get_user_bitmap(BMP_BG,&bitmap);
          create_bmp_layer( p_win, BMP_BG,0, 0, bitmap.height, bitmap.width );
          //冒号-once
          res_get_user_bitmap(BMP_COLON,&bitmap);
          GRect rc;
          fillGRect( &rc, 2*WATCH_NUM_SIZE.w, ORGIN_Y, bitmap.height, bitmap.width  );
          create_bmp_layer( p_win, BMP_COLON, rc.origin.x, rc.origin.y,rc.size.h,rc.size.w );
          //秒
          update_second_layer( datetime.sec );
          //时,分
          update_hour_min_layer( &datetime );
          //月,日年
          update_mondayyear_layer(&datetime);
          //星期几
          update_wday_layer( &datetime );
          //电量 
          update_battery_layer();
          //English time 
          update_english_layer( &datetime);
         //线-once
          Geometry *p_geo[1]; 
          uint8_t num = 0;
          LayerGeometry layer_geometry; 
          memset(p_geo, 0, sizeof(p_geo));
          Line line[] =     { {{0,13},{127,13}},   {{0,31},{127,31}},  {{0,32},{127,32}},   {{0,90},{127,90}},  {{0,91},{127,91}} };
          LineSet ls = {sizeof(line)/sizeof(*line), line};
          Geometry alg = {GeometryTypeLineSet, FillOutline, GColorWhite, (void*)&ls}; 
          p_geo[num++] = &alg;   
          layer_geometry.num = num;
          layer_geometry.p_g = p_geo;
          P_Layer         layer = app_layer_create_geometry(&layer_geometry);
          app_window_add_layer(p_win, layer);

          //显示秒定时器
          timer_id=app_window_timer_subscribe(p_win, 500, sec_callback, 0);
          maibu_service_sys_event_subscribe(time_change_callback);
          app_window_click_subscribe(p_win, ButtonIdBack,  on_back_key);
         //ButtonIdDown ButtonIdUp ButtonIdBack,ButtonIdSelect
          app_window_update(p_win);
          if (p_win != NULL) win_id= app_window_stack_push(p_win);
          //.................................................................................
          #ifdef USE_SIMULATOR
               simulator_wait();
          #endif
          return 0;
}



// 有两种情况会产生一个implicit declaration of function 的警告
// 1  没有把函数所在的c文件生成.o目标文件
// 2  在函数所在的c文件中定义了,但是没有在与之相关联的.h文件中声明

第四步.编译生成,模拟效果图


重编译表盘版本,将生成OUT.MAI文件,

改名成OUT.MP3,通过蓝牙传到手机上,再改名回OUT. MAI,

用麦步手机APP打开此文件,点击依旧安装,片刻即可安装成功

备注:

表盘第一行显示英文 月份日期,年份

第二行显示英文星期几,电量

中间高对比度显示24小时制时间

第三第四行显示英文时间

表盘切换或按后退键可以显示3分钟的秒,3分钟后,或者再按后退键自动消失,省电


表盘MAI文件下载:http://pan.baidu.com/s/1jHPny0e



评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值