智能电子牌——设备端
1. 说明
设备端所有源码均在文件夹electronic_board中,本文针对部分重点源码做出解释,同时本文介绍的代码更多地展示了代码的构建思路,若想直接使用对应函数请查看源代码。
2. 程序的入口函数
通过本函数开启智能电子牌的服务:
void ElectronicBoardAbility::OnStart(const Want &want)
{
SetMainRoute("ElectrBoardAbilitySlice");
Ability::OnStart(want);
}
3. UI页面中文字标签的设置
下面举例说明了一般UI界面中文字标签如何进行设置,如下是我们智能电子牌页面中”我的家“大标题的设置过程:
void ElectrBoardAbilitySlice::SetTitle() {
labelTitle_ = new UILabel();
labelTitle_->SetPosition(TITLE_XPOS, TITLE_YPOS, TITLE_WIDTH, TITLE_HEIGHT);
labelTitle_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT,
UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
labelTitle_->SetFont((const char *)FONT_PATH, TITLE_FONT);
labelTitle_->SetStyle(STYLE_TEXT_COLOR, Color::ColorTo32(Color::White()));
labelTitle_->SetStyle(STYLE_BACKGROUND_OPA, OPATICY_ALL);
labelTitle_->SetText("我的家");
rootview_->Add(labelTitle_);}
4. 循环任务如何实现
我们在通过sntp协议获取时间更新UI界面时,不停地从云端获取刷新日程信息时,这些任务都是在不停的循环进行的,如下是循环任务进行的一般写法:
class ScheduleListTask : public Task {
public:
ScheduleListTask(WeatherTimeView *tmView, ScheduleListView *view,
List<ScheduleInfo> *list)
: weatherTimeView(tmView), scheduleView(view), itemList(list) {
curIdx = -1;
Task::Init();
}
~ScheduleListTask() {}
void TaskStart() {
Task::SetPeriod(1000); /* 1000=1s */
Task::TaskExecute();
}
void SetList(List<ScheduleInfo> *list) { itemList = list; }
void Callback() override {
int idx = GetCurrentIdx();
if (idx >= 0 && idx != curIdx) {
SetScrollViewIdx(idx);
curIdx = idx;
}
}
private:
List<ScheduleInfo> *itemList{nullptr};
ScheduleListView *scheduleView{nullptr};
WeatherTimeView *weatherTimeView{nullptr};
static constexpr int ONE_HOUR = 60;
int curIdx;
int GetCurrentIdx() {
int retval = -1;
int i = 0;
int hour = 0;
int minute = 0;
weatherTimeView->GetTime(&hour, &minute);
if (itemList == nullptr || itemList->Size() == 0) {
return -1;
}
ListNode<ScheduleInfo> *pNode = itemList->Head();
for (i = 0; i < itemList->Size(); i++) {
if (pNode == nullptr) {
return -1;
}
if ((hour * ONE_HOUR + minute) <
(pNode->data_.getEndTimeHours() * ONE_HOUR +
pNode->data_.getEndTimeMinutes())) {
retval = i;
break;
}
pNode = pNode->next_;
}
if (i == itemList->Size()) {
retval = itemList->Size() - 1;
}
return retval;
}
void SetScrollViewIdx(int idx) {
if (scheduleView == nullptr) {
return;
}
scheduleView->ScheduleListViewSetSelect(idx);
scheduleView->ScheduleListViewNotify();
}
};
上述代码段是日程更新进行的一个类,之后我们在给该类创建对象,传入初始参数,然后引用任务开始函数即可,代码段如下:
scheduleTask_ = new ScheduleListTask(weatherTimeView_, scheduleView_, &scheduleList_);
scheduleTask_->TaskStart();
5. 日程提醒的实现思路
我们通过sntp获取实时时间,与同时获取时间选择器中的实时被选数据,通过转换将两者转化为同一种数据类型,之后进行比较,当两者相等时我们便可以使日程提醒信息弹出,但此时有一个重点需要注意,即我们通过sntp获取时间最好只例化一次,因为如果两个任务同时向服务器发起请求会发生拥挤,导致我们的智能电子牌会变的非常卡顿。日程实现的部分代码如下:
//构建了一个任务类型的类
class AlarmTimer : public Task {
//获取系统时间和定时器时间;进行两个时间的判断;实现子视图的添加和删除
public:
AlarmTimer(UITimePicker *uitimer, RootView *root, UILabel *label,
UILabel *label_tital, WeatherTimeView *tmView)
: timer(uitimer), rooter(root), labeler(label),
labeler_tital(label_tital), weatherTimeView(tmView) {
flag_timer = 0;
Task::Init();
}
~AlarmTimer() {}
void TaskStart() {
Task::SetPeriod(1000); /* 1000=1s */
Task::TaskExecute();
}
void Callback() override {
const char *flag_h = new char[3];
const char *flag_m = new char[3];
int h = 0;
int m = 0;
int h_ = 0;
int m_ = 0;
struct tm rtcTime;
int netConnect = SystemGetNetStatus();
weatherTimeView->GetTime(&h, &m);
if (netConnect != 1) {
if (SystemGetTime(&rtcTime) < 0) {
return;
}
h = rtcTime.tm_hour;
m = rtcTime.tm_min;
}
flag_h = timer->GetSelectHour();
flag_m = timer->GetSelectMinute();
h_ = ((int)flag_h[0] - 0x30) * 10 + ((int)flag_h[1] - 0x30);
m_ = ((int)flag_m[0] - 0x30) * 10 + ((int)flag_m[1] - 0x30);
printf("[S:h][%d] \n", h);
printf("[P:h_][%d] \n", h_);
printf("[S:m][%d] \n", m);
printf("[P:m_][%d] \n", m_); //在串口观察实际数据
printf("[flag_timer:][%d] \n", flag_timer);
if (((h == h_) && (m == m_))) {
if (flag_timer == 0) {
rooter->Add(labeler);
flag_timer = 1;
} else
return;
} else {
if (flag_timer == 1) {
flag_timer = 0;
rooter->Remove(labeler);
} else
return;
}
}
private:
WeatherTimeView *weatherTimeView{nullptr};
RootView *rooter{nullptr};
UITimePicker *timer{nullptr};
UILabel *labeler{nullptr};
UILabel *labeler_tital{nullptr};
int flag_timer;
};
如下是日程提醒的UI实现与任务的开始:
void ElectrBoardAbilitySlice::SetTimerView() {
timer_ = new UITimePicker();
timer_->SetPosition(Timer_X, Timer_Y, Timer_W, Timer_H);
timer_->SetItemHeight(Timer_item_H);
rootview_->Add(timer_);
alarmlabel_ = new UILabel();
alarmlabel_->SetPosition(Timer_TEXT_X,Timer_TEXT_Y,Timer_TEXT_WIDTH,Timer_TEXT_HEIGHT);
alarmlabel_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER,
UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
alarmlabel_->SetFont((const char *)FONT_PATH, ALARM_FONT);
alarmlabel_->SetStyle(STYLE_TEXT_COLOR, Color::ColorTo32(Color::Red()));
alarmlabel_->SetText("日程时间到了!");
alarmtimer_ = new AlarmTimer(timer_, rootview_, alarmlabel_,labelTitle_,weatherTimeView_);
alarmtimer_->TaskStart();
}
6. 实时时间的获取
智能电子牌时间的获取是使用了sntp协议于服务器主动获取对应的实时时间,如下是向服务器请求的具体实现:
#ifndef NTP_SERVER_IP
#define NTP_SERVER_IP "120.24.166.46"
#endif
#ifndef NTP_SERVER_PORT
#define NTP_SERVER_PORT 123
#endif
int SntpGetRtcTime(int localTimeZone, struct tm *rtcTime)
{
int ret = -1;
int sockfd = -1;
struct sockaddr_in server;
socklen_t addrLen;
fd_set set;
struct timeval timeout;
struct timeval t