/* 功能:将TAG_VALUE实时值写入设备。 参数: name 待写入实时值对应的 组名.标签名 value 待写入的实时值 返回:即设备驱动导出函数write_device()的返回值 */ IO_API __bool PMC_API io_write_device( PCSHORT_TAG_NAME name, PCTAG_VALUE value ) { __bool retval = __false; //1 锁定 if(!lock_rtdb(__false, 100)){ return __false; } //2 找到本地节点中的指定标签点的RTK_TAG,其中存有该标签点对应的设备信息 PRTK_TAG p = query_tag(HNODE_LOCAL_MACHINE, name); //3 将单点单实时值写入设备 if(p && !(p->d.Value.Flags & TF_ReadOnly)){ #if 0 { char valbuf[32]; if(get_value_type(p->s.Flags) == dt_real4){ sprintf(valbuf, "%f", value->fltValue); }else{ sprintf(valbuf, "%s", value->iValue? "On" : "Off"); } utils_debug( "WriteDevice(%s.%s)=%s\n", (char *)CGroupName(name->group), (char *)CTagName(name->tag), valbuf ); } #endif //调用设备驱动导出函数,将单点单实时值写入设备 retval = _writeDevice(p, value); } //4 解锁 unlock_rtdb(); return retval; }
//--------------------------------------------------------------------------- void __fastcall TframTag::btnWriteDeviceClick(TObject *Sender) { AnsiString value; pmc_value_t strVal, val; value = InputBox( "输入要写的数值", (char*)CTagName(m_TagName.sname.tag), "" ); if(value.Length() == 0){ return; } set_value_type(strVal.Flags, dt_string); strVal.Value.str = value.c_str(); val.Flags = m_Tag.s.Flags; pmc_type_cast(&strVal, &val); if(proxy_write_tags(1, &m_TagName, &val.Value) ){ m_Hint = "写入成功"; }else{ m_Hint = "写入失败"; } }
PROXY_API __uint PMC_API update_changed_data( PCRTK_PACKET packet, __bool bThisIsAServer ) { CHANGED_DATA_ENTRY * t; CHANGED_DATA * cd; __uint i, nMissing; RTK_CURSOR hNode, hGroup, hTag; TAG_NAME name; PRTK_TAG pTag; __uint retcount = 0; TAG_NAME missing[MAX_MISSING_PERMITED]; if(packet->data_size <= sizeof(CHANGED_DATA)){ return 0; } cd = (CHANGED_DATA*)packet->data; t = (CHANGED_DATA_ENTRY*)&cd[1]; if(packet->data_size != cd->count * sizeof(CHANGED_DATA_ENTRY) + sizeof(CHANGED_DATA) ){ return 0; } #if 0 for(i=0; i<cd->count; i++){ utils_debug("%s.%s.%s=%f\n", (char*)CHostName(packet->src.host), (char*)CGroupName(cd->group), (char*)CTagName(t[i].name), t[i].value.Value.fltValue ); } #endif memset(&name, 0, sizeof(name)); host_to_node(&packet->src.host, &name.node); name.sname.group = cd->group; if(!lock_rtdb(__false, 100)){ return 0; } if(bThisIsAServer){ if(!(packet->src.host == g_ThisNode->key)){ unlock_rtdb(); return 0; } hNode = HNODE_LOCAL_MACHINE; }else{ hNode = open_node(&name.node); } if(!hNode){ unlock_rtdb(); return 0; } hGroup = open_group(hNode, &cd->group); if(!hGroup){ if(!bThisIsAServer){ close_handle(hNode); } unlock_rtdb(); if(g_Worker){ g_Worker->inform_load(&name, 1); } // 2003/5/27, in current implementation all following // tags are guaranteed to be in the same group, so there // is no need to proceed. return 0; } nMissing = 0; for(i=0; i<cd->count; i++){ hTag = open_tag_g(hGroup, &t[i].name); if(hTag){ pTag = (PRTK_TAG)cursor_get_item(hTag); pTag->d.Value = t[i].value; // pTag->d.Value.Flags = t[i].value.Flags; mark_fresh(pTag); close_handle(hTag); retcount++; }else{ if(g_Worker && nMissing < MAX_MISSING_PERMITED){ name.sname.tag = t[i].name; missing[nMissing] = name; nMissing++; } } } close_handle(hGroup); if(!bThisIsAServer){ close_handle(hNode); } unlock_rtdb(); if(nMissing && g_Worker){ if(nMissing > 16){ memset(&missing[0].sname.tag, 0, sizeof(TAG_KEY)); g_Worker->inform_load(missing, 1); }else{ g_Worker->inform_load(missing, nMissing); } } return retcount; }
/* Load data from storage to UI */ void __fastcall TframTag::UpdateView() { //TODO: Add your source code here TComponent * comp; int i; PTAG_NAME name = &m_TagName; // update static information PRTK_TAG pTag = &m_Tag; char textname[TAGNAME_TEXT_LENGTH + 1]; char buf[64]; // temporarily disable unapplicable components tsException->TabVisible = false; btnWriteDevice->Enabled = (pTag->d.Value.Flags & TF_ReadOnly)? false : true; // now we update the UI to reflect the tag configuration /* 0 开关量 1 模拟量 2 高精度模拟量 3 8位整数 4 16位整数 5 32位整数 6 64位整数 7 无符号8位整数 8 无符号16位整数 9 无符号32位整数 10 无符号64位整数 11 日期 */ cmbType->OnChange = NULL; switch(get_value_type(pTag->s.Flags)){ case dt_bool: cmbType->ItemIndex = 0; break; case dt_real4: cmbType->ItemIndex = 1; break; case dt_real8: cmbType->ItemIndex = 2; break; case dt_int8: cmbType->ItemIndex = 3; break; case dt_int16: cmbType->ItemIndex = 4; break; case dt_int32: cmbType->ItemIndex = 5; break; case dt_int64: cmbType->ItemIndex = 6; break; case dt_uint8: cmbType->ItemIndex = 7; break; case dt_uint16: cmbType->ItemIndex = 8; break; case dt_uint32: cmbType->ItemIndex = 9; break; case dt_uint64: cmbType->ItemIndex = 10; break; case dt_date: cmbType->ItemIndex = 11; break; default: cmbType->ItemIndex = 12; break; } cmbType->OnChange = cmbTypeChange; { cmbDevice->Ctl3D = false; CDeviceItems * ditems; AnsiString Url; Url = (char*)CNodeName(name->node); Url += ".DEVICES"; ditems = dynamic_cast<CDeviceItems*>(g_DCS.Search(Url)); if(ditems){ if(!ditems->m_iRefreshCount){ ditems->Refresh(); } } cmbDevice->Items->Clear(); cmbDevice->Text = ""; if(ditems){ CDeviceItem * ditem; ditem = dynamic_cast<CDeviceItem*>(ditems->GetFirstChild()); while(ditem){ cmbDevice->Items->Add((char*)CDeviceName(ditem->info.k)); ditem = dynamic_cast<CDeviceItem*>(ditems->GetNextChild(ditem)); } } } { PRTK_GROUP pgrp; RTK_CURSOR hgrp; hgrp = open_group_f(&name->node, &name->sname.group); pgrp = (PRTK_GROUP)cursor_get_item(hgrp); if(pgrp){ if(pgrp->period > 50){ tmrUpdater->Interval = pgrp->period; } } close_handle(hgrp); } edtTagName->Text = (char *)CTagName(name->sname.tag); edtCName->Text = pTag->s.Description; edtAddr->Text = pTag->s.Address; cmbDevice->Text = (char*)CDeviceName(pTag->s.Device); #define cc(name) \ do{ if(pTag->s.Flags & TF_##name){\ chk##name->Checked = true;\ }else{\ chk##name->Checked = false;\ }\ }while(0) cc(HiHi); cc(Lo); cc(Hi); cc(LoLo); cc(On2Off); cc(Off2On); cc(Rate); cc(SaveToHistory); cc(Step); /* // cutoff is obsolete #define dd(name) chk##name->Checked = pTag->s.CutOffMask & TF_##name ? true : false; dd(HiHi); dd(Lo); dd(Hi); dd(LoLo); dd(On2Off); dd(Off2On); */ if(pTag->s.Flags & TF_System){ cmbDevice->Enabled = false; edtAddr->ReadOnly = true; cmbType->Enabled = false; cmbDevice->Color = clScrollBar; edtAddr->Color = clScrollBar; cmbType->Color = clScrollBar; }else{ cmbDevice->Enabled = true; edtAddr->ReadOnly = false; cmbType->Enabled = true; cmbType->Color = clWindow; cmbDevice->Color = clWindow; edtAddr->Color = clWindow; } switch(get_value_type(pTag->s.Flags)){ case dt_real4: case dt_real8: case dt_int64: case dt_uint64: #define aa(f) sprintf(buf, "%g", pTag->s.flt##f);edt##f->Text = buf; aa(HiHi); aa(Hi); aa(Lo); aa(LoLo); aa(AlarmDeadband); aa(MaxValue); aa(MinValue); aa(Rate); edtEU->Text = pTag->s.AnalogMsg.EU; tsAnalog->TabVisible = true; tsLogical->TabVisible = false; break; case dt_int8: case dt_int16: case dt_int32: case dt_uint8: case dt_uint16: case dt_uint32: aa(AlarmDeadband); aa(Rate); #undef aa #define aa(v, name) \ sprintf(buf, "%d", pTag->s.v);\ edt##name->Text = buf; aa(u_hihi.i, HiHi); aa(u_hi.i, Hi); aa(u_lo.i, Lo); aa(u_lolo.i, LoLo); aa(u_max.i, MaxValue); aa(u_min.i, MinValue); edtEU->Text = pTag->s.AnalogMsg.EU; tsAnalog->TabVisible = true; tsLogical->TabVisible = false; break; case dt_date: tsArchive->TabVisible = true; tsAnalog->TabVisible = false; tsLogical->TabVisible = false; break; case dt_bool: edtOnMessage->Text = pTag->s.SwitchMsg.OnMsg; edtOffMessage->Text = pTag->s.SwitchMsg.OffMsg; tsLogical->TabVisible = true; tsAnalog->TabVisible = false; default: assert(0); break; } tsAnalog->Visible = tsAnalog->TabVisible; tsLogical->Visible = tsLogical->TabVisible; tsException->Visible = tsException->TabVisible; tsArchive->Visible = tsArchive->TabVisible; edtAlarmRank->Text = pTag->s.AlarmRank; edtAlarmRank2->Text = pTag->s.AlarmRank; chkCompressing->Checked = true; edtCompMax->Enabled = chkCompressing->Checked; edtCompDev->Enabled = chkCompressing->Checked; edtCompDevPercent->Enabled = chkCompressing->Checked; edtCompMax->Text = IntToStr(pTag->s.CompMax); edtCompDev->Text = FloatToStr(pTag->s.CompDev); __r8 span = _getSpan(pTag); if(span > 1e-5){ edtCompDevPercent->Text = FloatToStr(pTag->s.CompDev / span * 100); } TAG_NAME ctn; ZeroMemory(&ctn, sizeof(ctn)); ctn.sname = pTag->s.CutOffTagName; tagname_to_text(&ctn, textname, sizeof(textname)); // debugging output { char nn[128]; *nn=0; #define __check_field__(field,name) \ if(pTag->d.Value.Flags & TF_##field) {\ if(*nn) {\ strcat(nn,"+");\ strcat(nn,#name);\ }else{\ strcpy(nn,#name);\ }\ } __check_field__(HiHi,h2) __check_field__(Hi,h) __check_field__(LoLo,l2) __check_field__(Lo,l) __check_field__(Rate,r) __check_field__(On2Off,off) __check_field__(Off2On,on) __check_field__(Alarm,alarm) __check_field__(Expired,expired) __check_field__(SharpChange,sharp) __check_field__(ReadOnly,read) __check_field__(Translated,trans) __check_field__(ConfigOk,ok) __check_field__(Valid,valid) utils_debug("%s flags=0x%08x,%s\n", textname, pTag->d.Value.Flags, nn); #undef __check_field__ } // pg->Clear(); }
/* gather data from UI to internal representation */ bool TframTag::ValidateView() { PTAG_NAME name; PRTK_TAG tag; name = &m_TagName; tag = &m_Tag; try{ #undef cc #define cc(name) tag->s.Flags |= (chk##name->Checked ? TF_##name : 0); if( edtTagName->Text.Length() >sizeof(TAG_KEY) || !edtTagName->Text.Length() ){ m_Hint = "变量名不正确"; throw(-1); } if( !is_valid_name(edtTagName->Text.c_str()) ){ m_Hint = "变量名只能包含字母、数字和下划线"; throw(-3); } if(edtTagName->Text.Length() > sizeof(TAG_KEY)){ m_Hint = AnsiString("错误: 标签名不能超过 ") + IntToStr(sizeof(TAG_KEY)) + " 个字节"; throw(-3); } name->sname.tag = CTagName(edtTagName->Text.c_str()); tag->s.Device = CDeviceName(cmbDevice->Text.c_str()); tag->key = name->sname.tag; if(edtCName->Text.Length() > sizeof(tag->s.Description)){ m_Hint = "中文名太长(最长 " + AnsiString(sizeof(tag->s.Description)/2) + " 字)"; throw(-4); } strncpy(tag->s.Description, edtCName->Text.c_str(), sizeof(tag->s.Description)); tag->s.Description[sizeof(tag->s.Description) - 1] = 0; if(edtAddr->Text.Length() > sizeof(tag->s.Address)){ m_Hint = "地址太长(最长 " + AnsiString(sizeof(tag->s.Address)/2) + " 字)"; throw(-5); } strncpy(tag->s.Address, edtAddr->Text.c_str(), sizeof(tag->s.Address)); tag->s.Address[sizeof(tag->s.Address) - 1] = 0; tag->s.Flags = 0; switch(cmbType->ItemIndex){ case 0: set_value_type(tag->s.Flags, dt_bool); break; case 1: set_value_type(tag->s.Flags, dt_real4); break; case 2: set_value_type(tag->s.Flags, dt_real8); break; case 3: set_value_type(tag->s.Flags, dt_int8); break; case 4: set_value_type(tag->s.Flags, dt_int16); break; case 5: set_value_type(tag->s.Flags, dt_int32); break; case 6: set_value_type(tag->s.Flags, dt_int64); break; case 7: set_value_type(tag->s.Flags, dt_uint8); break; case 8: set_value_type(tag->s.Flags, dt_uint16); break; case 9: set_value_type(tag->s.Flags, dt_uint32); break; case 10: set_value_type(tag->s.Flags, dt_uint64); break; case 11: set_value_type(tag->s.Flags, dt_date); break; case 12: m_Hint = "不支持这个数据类型."; throw(-41); break; } cc(SaveToHistory); cc(Step); // collecting common analog attributes switch(get_value_type(tag->s.Flags)){ case dt_int8: case dt_int16: case dt_int32: case dt_int64: case dt_uint8: case dt_uint16: case dt_uint32: case dt_uint64: case dt_real4: case dt_real8: case dt_date: cc(HiHi); cc(Lo); cc(Hi); cc(LoLo); cc(Rate); strncpy( tag->s.AnalogMsg.EU, edtEU->Text.c_str(), sizeof(tag->s.AnalogMsg.EU) ); tag->s.AnalogMsg.EU[sizeof(tag->s.AnalogMsg.EU) - 1] = 0; break; case dt_bool: cc(On2Off); cc(Off2On); strncpy( tag->s.SwitchMsg.OnMsg, edtOnMessage->Text.c_str(), sizeof(tag->s.SwitchMsg.OnMsg) ); tag->s.SwitchMsg.OnMsg[sizeof(tag->s.SwitchMsg.OnMsg) - 1] = 0; strncpy( tag->s.SwitchMsg.OffMsg, edtOffMessage->Text.c_str(), sizeof(tag->s.SwitchMsg.OffMsg) ); tag->s.SwitchMsg.OffMsg[sizeof(tag->s.SwitchMsg.OffMsg) - 1] = 0; break; } #define get(msg, name, ignore_on_condition, _default_value)\ m_Hint = msg;\ if( !edt##name->Text.Length() ){\ if(ignore_on_condition){\ tag->s.flt##name = _default_value;\ }else{\ throw(-1);\ }\ }else{\ tag->s.flt##name = edt##name->Text.ToDouble();\ } #pragma warn -ccc #pragma warn -rch switch(get_value_type(tag->s.Flags)){ case dt_real4: case dt_real8: get("高高值不正确", HiHi, !chkHiHi->Checked, 0); get("低低值不正确", LoLo, !chkLoLo->Checked, 0); get("低值不正确", Lo, !chkLo->Checked, 0); get("高值不正确", Hi, !chkHi->Checked, 0); get("报警死区值不正确", AlarmDeadband, !(tag->s.Flags & 0xffffff00), 0); get("最大值不正确", MaxValue, false, 0); get("最小值不正确", MinValue, false, 0); get("速率报警阈值不正确", Rate, !chkRate->Checked, 0.1); break; case dt_int8: case dt_int16: case dt_int32: case dt_int64: case dt_uint8: case dt_uint16: case dt_uint32: case dt_uint64: get("速率报警阈值不正确", Rate, !chkRate->Checked, 0.1); #undef get #define get(msg, attrName, uiName, ignore_on_condition, _default_value)\ m_Hint = msg;\ if( !edt##uiName->Text.Length() ){\ if(ignore_on_condition){\ tag->s.##attrName = _default_value;\ }else{\ throw(-1);\ }\ }else{\ tag->s.attrName = edt##uiName->Text.ToDouble();\ } get("高高值不正确", u_hihi.i, HiHi, !chkHiHi->Checked, 0); get("低低值不正确", u_lolo.i, LoLo, !chkLoLo->Checked, 0); get("低值不正确", u_lo.i, Lo, !chkLo->Checked, 0); get("高值不正确", u_hi.i, Hi, !chkHi->Checked, 0); get("报警死区值不正确", u_deadband.i, AlarmDeadband, !(tag->s.Flags & 0xffffff00), 0); get("最大值不正确", u_max.i, MaxValue, false, 0); get("最小值不正确", u_min.i, MinValue, false, 0); break; } #pragma warn .ccc #pragma warn .rch if(get_value_type(tag->s.Flags) == dt_bool){ tag->s.AlarmRank = edtAlarmRank2->Text.ToInt(); }else{ tag->s.AlarmRank = edtAlarmRank->Text.ToInt(); } tag->s.Compressing = Compress_Const; tag->s.CompDev = StrToFloat(edtCompDev->Text); tag->s.CompMax = StrToInt(edtCompMax->Text); }catch(...){ return false; } m_Hint = "更新成功"; return true; }