前不久,出了一件怪事,不知道是太阳风暴,还是恰逢农历闰六月的,
还是其他原因引起,
我的手表开始不断死机重启.
正想是不是联系售后寄回去时,
我发现了只要切换别的表盘就一切正常了,
再切换回"超清时钟"表盘有就立出现故障,
无奈只好忍痛割爱.
之后发现官方也把这个表盘下架了.
一时间再也找不到代替的时钟表盘.于是只好自己动手丰衣足食,自己做一个.
第一步:找素材
上官方淘宝评论找"高清时钟"的表盘图片,为了凑齐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