机械境

这里只是我的后花园,随性而写

缘起

由于众所周知的原因,也就是 Apple 的云真的很烂,App Store 还能通过 DNS 等手段加速更新。对于 XCode 简直就是噩梦,挂不挂都是一个样子,非常慢。不幸中之大幸,虽然 XCode 本身下载很慢,但是可以手动下载好之后,通过 XCode 安装。

文档

手动下载文档可以通过以下几步解决,via stackoverflow

  1. 通过这个地址找到需要下载的文件的路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- START OS X doc set -->
<dict>
<key>fileSize</key>
<integer>931959772</integer>
<key>identifier</key>
<string>com.apple.adc.documentation.OSX</string>
<key>name</key>
<string>OS X 10.11.4 Documentation</string>
<key>source</key>
<string>https://devimages.apple.com.edgekey.net/docsets/20160321/031-52211-A.dmg</string>
<key>userInfo</key>
<dict>
<key>ActivationPredicate</key>
<string>$XCODE_VERSION &gt;= '7.3'</string>
<key>Category</key>
<string>Documentation</string>
<key>IconType</key>
<string>IDEDownloadablesTypeDocSet</string>
<key>InstallPrefix</key>
<string>$(HOME)/Library/Developer/Shared/Documentation/DocSets</string>
<key>InstalledIfAllReceiptsArePresentOrNewer</key>
<dict>
<key>com.apple.pkg.10.9.OSXDocset</key>
<string>10.9.0.0.1.1458364023</string>
</dict>
<key>RequiresADCAuthentication</key>
<false/>
<key>Summary</key>
<string>My description of content</string>
</dict>
<key>version</key>
<string>1014.5</string>
</dict>
<!-- END OS X doc set -->
下载 `source` 节点对应的内容,在这个示例中也就是[这个](https://devimages.apple.com.edgekey.net/docsets/20160321/031-52211-A.dmg),可以通过第三方的下载工具,比如 asia2 下载。
  1. 按照 identifier string + - + version string + .dmg 的格式重命名文件,在这个示例中也就是 com.apple.adc.documentation.OSX-1014.5.dmg

  2. 把重命名后的文件放到 ~/Library/Caches/com.apple.dt.Xcode/Downloads/ 中,如果没有 Downloads 文件夹就创建一个,
    如果 Downloads 中有后缀为 dvtdownloadableindex 的文件,全部删除

  3. 删除 ~/Library/Developer/Shared/Documentation/DocSets 中对应的 docset

  4. 在 XCode 中 Preferences/Download 中下载对应的文档,XCode 会校验刚才复制过去的文件进行安装

模拟器

  1. 打开 XCode,Preferences/Download 中下载模拟器
  2. 打开 Console.app,清空日志
  3. 在 XCode 中取消下载
  4. 在 Console.app 中会看到取消的日志,其他包含完整的下载地址
  5. 通过 asia2 等第三方工具下载刚才地址中的文件
  6. 把下载好的文件复制到 ~/Library/Caches/com.apple.dt.Xcode/Downloads 中,如果没有 Downloads 文件夹就创建一个,
    如果 Downloads 中有后缀为 dvtdownloadableindex 的文件,全部删除
  7. 在 XCode 中安装刚才下载的模拟器

如果需要删除不需要的模拟器,可以在 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs 中直接删除

—EOF—

介绍

MSYS2 是 MSYS 的一个升级版,准确的说是集成了 pacman 和 Mingw-w64 的 Cygwin 升级版。与 MSYS 最大的区别是移植了 Pacman。

比较

特点 Cygwin MinGW/MSYS MSYS2
是否 GNU
软件支持? 支持绝大多数的 GNU 软件 支持常用软件 支持大多数 GNU 软件
更类似 Linux? 在 Windows 中模拟 Linux 实现了 Bash 等主要的 Linux 程序 原生 64/32bit 支持
GCC 编译 独立的 Windows/Linux 程序编译 (MingGW32 交叉编译 / 依赖 cygwin1.dll) 独立的 Windows 程序编译 独立的 Windows 程序编译
中文支持 直接支持中文显示和输入法 需要配置才能支持中文显示和输入,删除一个中文字符需要删除 2 次 支持中文显示和输入法,中文帮助系统和中文提示(部分软件)
运行速度

安装

安装 MSYS2

从官网下载 MSYS2 安装文件,一路 Next 即可。

安装开发环境

pacman -S --needed base-devel msys2-devel mingw-w64-x86_64-toolchain

配置

环境变量

1
2
3
MSYS_HOME=D:\msys64
MINGW_HOME=D:\msys64\mingw64
LIBRARY_PATH=D:\msys64\mingw64\lib

镜像配置

如果网络环境不好的话,可以增加国内的镜像,速度改进非常明显。

修改 /etc/pacman.d/ 文件夹中修改 mirrorlist 开头的三个文件:

  • mirrorlist.mingw32
1
2
3
4
5
6
7
8
9
10
##
## 32-bit Mingw-w64 repository mirrorlist
##
Server=http://mirrors3.ustc.edu.cn/msys2/REPOS/MINGW/i686

## Primary
## msys2.org
Server = http://repo.msys2.org/mingw/i686
Server = http://downloads.sourceforge.net/project/msys2/REPOS/MINGW/i686
Server = http://www2.futureware.at/~nickoe/msys2-mirror/i686/
  • mirrorlist.mingw64
1
2
3
4
5
6
7
8
9
10
11
##
## 64-bit Mingw-w64 repository mirrorlist
##

Server=http://mirrors3.ustc.edu.cn/msys2/REPOS/MINGW/x86_64
## Primary
## msys2.org
Server = http://repo.msys2.org/mingw/x86_64
Server = http://downloads.sourceforge.net/project/msys2/REPOS/MINGW/x86_64
Server = http://www2.futureware.at/~nickoe/msys2-mirror/x86_64/

  • mirrorlist.msys
1
2
3
4
5
6
7
8
9
10
11
##
## MSYS2 repository mirrorlist
##

Server=http://mirrors3.ustc.edu.cn/msys2/REPOS/MSYS2/$arch

## Primary
## msys2.org
Server = http://repo.msys2.org/msys/$arch
Server = http://downloads.sourceforge.net/project/msys2/REPOS/MSYS2/$arch
Server = http://www2.futureware.at/~nickoe/msys2-mirror/msys/$arch/

代理

如果需要通过代理才能上网的话,可以在 /etc/profile.d/ 增加 proxy.sh,内容如下:

1
2
3
4
5
6
export http_proxy=%PROXY_SERVER%:%PROXY_PORT%
export https_proxy=%PROXY_SERVER%:%PROXY_PORT%
export ftp_proxy=%PROXY_SERVER%:%PROXY_PORT%
export HTTP_PROXY=%PROXY_SERVER%:%PROXY_PORT%
export HTTPS_PROXY=%PROXY_SERVER%:%PROXY_PORT%
export FTP_PROXY=%PROXY_SERVER%:%PROXY_PORT%

用户目录

修改 /etc/fstab,映射用户目录,与宿主共享配置,这样类似 gitconfig 这样的配置只需要配置一份。

1
2
3
4
5
6
# For a description of the file format, see the Users Guide
# http://cygwin.com/cygwin-ug-net/using.html#mount-table

# DO NOT REMOVE NEXT LINE. It remove cygdrive prefix from path
none / cygdrive binary,posix=0,noacl,user 0 0
C:/Users /home ntfs binary,noacl,auto 1 1

公用 HOME 目录

环境变量中添加 MSYS2_PATH_TYPE 值为 inherit

包管理

  • 刷新软件包 pacman -Sy

  • 安装新包 pacman -S <package_names|package_groups>

  • 删除 pacman -R <package_names|package_groups>

  • 搜索 pacman -Ss <name_pattern>

更多请参考 Arch Linux wiki.

安装 zshoh my zsh

  • 安装 zsh
1
2
pacman -Syu
pacman -S zsh
  • 安装 oh my zsh
1
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

zsh 的配置文件是 ~/.zshrc,可以通过编辑这个文件来指定主题,插件。

重新安装

如果在使用过程中, MSYS2 出现不可恢复的问题的时候,可以通过保存安装的 packages 到文件中,再通过此文件重新安装。

  • 保存现有安装包列表到 C 盘中的 packages.txt

pacman -Qqe | xargs echo > /c/packages.txt ; exit

  • 根据保存的 packages.txt 安装
1
2
3
pacman -Sy
pacman --needed -S bash pacman pacman-mirrors msys2-runtime
pacman -S --needed --force $(cat /c/packages.txt)

如果你使用 MacType 的话,请一定在 default.ini (MacType 的配置文件) 添加 gpg/pacman 的例外。

1
2
3
[UnloadDll]
gpg.exe
pacman.exe

via #393 GPGME error: Invalid crypto engine

如果你使用 VirtualBox 4.3.14+ 的话,也需要把相关进程排除。via VirtualBox 4.3.12 以后的 E_FAIL (0x80004005) 问题

—EOF—

问题

SourceTree 真是一个让人又爱又恨的产品,小问题不断,但是在免费的 Git 的 GUI 里面还算优秀的。因为 TortoiseGit 对 msys2 支持不好,我又回到 SourceTree 阵营了,SourceTree 为主, CLI 辅助。 因为 SourceTree 不能识别 msys2 的 Git,虽然其自带一个内嵌的 Git,这样就导致了我需要配置两份全局的 gitconfig。

解决方案

其实原因很简单,因为 SourceTree 要求 Git 所在目录必须同时有 bin 和 cmd 文件夹。听起来很 2 是吧?知道了原因要解决起来就很简单。

  1. 我的 msys2 安装在 d:\msys64,在 SourceTree 中选择 系统安装的 Git (工具 / 选项 / Git)

    在 AppData 中的 user.config 配置中 GitSystemPath 节点会自动识别出 msys2 的路径

    1
    2
    3
    <setting name="GitSystemPath" serializeAs="String">
    <value>D:\msys64\usr</value>
    </setting>
  2. 通过 mklink 建立一个链接

    D:\msys64\usr 建立链接
    mklink /D cmd bin

—EOF—

介绍

eDNA 是一个领导性的实时 / 历史数据系统。eDNA 采集、存储和展示大量的工程和运行信息。eDNA 将深入在整个企业范围内的数据采集上来,以极高的无损压缩方式存储起来,使得以时间序列频繁变化的数据能以原有的数据精度和时间精度在线保存多达几十年。eDNA 使基于运行状况的及时和准确的决策成为可能,极大地降低运行成本。eDNA 具有完全分布的体系结构,让正确的人在正确的时间做出正确的决定。eDNA 是一套实时的运行管理解决方案,它提供了对你的生产运行中无限制的观察和分析,使得你能够根据丰富的信息迅速地做出决策,你的一线生产能力将会大大提高。via 印步

API

eDNA 分为两种:

  • 常规 API:支持 C/C++/Visual Basic 等。这种方式需要自己组装报文,虽然有相关 API 函数支持,但是实际应用起来还是比较麻烦
  • EzDNA:封装了常用的操作,只需要引入一个头文件 (EzDnaApi.h) 即可。

注:两种方式都需要安装 eDNA 的 Client 程序。

示例代码

涉及到的 API 函数:

  • DNAGoodPointFormat 检查测点名称是否符合命名规范
  • DoesIdExist 检查测点是否存在
  • DNAGetRTFull 查询指定测点的实时数据
  • DNAGetHSFull 同上

注: DNAGetHSFull 查询到的时间精度是毫秒,如果对时间有要求,建议使用此函数。但是在实际使用过程中,发现此函数有时候会查询不到数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int16_t getsnapshot()
{
edna_tag_t *tag;
int32_t index;
int32_t *buff_size;
int16_t counter;
int32_t ret;
int8_t log_tag[MAX_BUFF_SIZE];
int8_t szValue[EDNA_LEN];
int32_t ptTime;

int8_t szmS[EDNA_LEN];
uint16_t pusStatus;
int8_t szStatus[EDNA_LEN];
int8_t szDesc[EDNA_DESC_LEN];
int8_t szUnits[EDNA_LEN];

strncpy(log_tag, "getsnapshot", MAX_BUFF_SIZE);
// init parameters
// ....

for (index = 0; index < ptbl_data->point_size; index++, tag++)
{
// other stuff
// ...

if (tag->flag == E_EMPTY_TAG) continue;

// tests the string, validating it as a fully qualified eDNA point name
if (DNAGoodPointFormat(tag->name) == 0)
{
tag->flag = INVALID;
continue;
}

// check point name is exist
if (!DoesIdExist(tag->name))
{
tag->flag = NOT_EXIST;
continue;
}

// retrieves the value, time and status in their raw formats
ret = DNAGetRTFull(tag->name, &tag->value, szValue, EDNA_LEN, &ptTime, tag->ts,
EDNA_LEN, &pusStatus, szStatus, EDNA_LEN, szDesc,
EDNA_DESC_LEN, szUnits, EDNA_LEN);

#if 0

ret = DNAGetHSFull(tag->name, &tag->value, szValue, EDNA_LEN, &ptTime, tag->ts,
EDNA_LEN, &tag->ms, szmS, EDNA_LEN, &pusStatus, szStatus,
EDNA_LEN, szDesc, EDNA_DESC_LEN, szUnits, EDNA_LEN);
#endif


tag->flag = (ret == 0) ? NORMAL : OFFLINE;
}

return TRUE;
}

—EOF—

介绍

PI(Plant Information System)是由美国 OSIsoft 公司开发的一套基于 Client/Server 结构的商品化软件应用平台,是过程工业全厂信息集成的必然选择。作为工厂底层控制网络与上层管理信息系统网络连接的桥梁,PI 在工厂信息集成中扮演着特殊和重要的角色。更详细的介绍,可参考百度百科或者官方网站

登录数据库

要访问数据库,有两种方法,一种是通过用户名和密码登录,另一种是通过 PI Trust。官方是不建议使用密码登录的,所以在开发应用的时候,尽可能使用 PI Trust,但是国内的情况比较混乱,很多生产环境都还是使用第一次方式。

下面分别介绍两种登录方法的使用

用户名 / 密码登录

这种方式比较简单,Server 端几乎不需要任何配置,只要简单添加一个用户即可。

涉及到的 API 函数:

  • piut_setservernode 设置 PI Server 节点,一般就是 Server 的 IP 地址
  • piut_isconnected 是否已经和 Server 连接
  • piut_login 传入用户名 / 密码,根据返回值判断是否连接成功,如果需要写数据的话,需要注意写权限

在 PI 3.x 中,默认是不启用用户名 / 密码登录的,需要注意

PI Trust 登录

这种方式,是官方推荐做法,需要在 Server 段添加相应的 PI Trust 设置,可以设置 IP 地址 / Client 名称 / 进程名字等,配置非常灵活。

涉及到的 API 函数:

  • piut_setservernode 同上
  • piut_isconnected 同上
  • piut_setprocname 设置 Client 的进程名,需要和 Server 段设置一致
  • piut_connect 连接 Server

示例代码,功能就是根据配置参数自动判断连接方式,因为我们生产环境是个很老的现场,所以优先使用用户名 / 密码登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
error_t connect_pi(server_info_t *server)
{
int32_t result;
int32_t valid;
int8_t version[SERVER_FIELD_SIZE];
int8_t log_tag[MAX_BUFF_SIZE];
int8_t pro_name[SERVER_FIELD_SIZE];

valid = PIREAD;

strncpy(log_tag, "connect pi", MAX_BUFF_SIZE);

if (piut_isconnected() == 0)
{
// retrieves the version number of the PI-API.
if (piut_getapiversion(version, sizeof(version)) == 0)
{
ftrace_log(log_tag, "PI-API version %s", version);
}

if (server->misc3 == NULL || strlen(server->misc3) == 0)
{
strncpy(pro_name, "pi_snap", SERVER_FIELD_SIZE);
}
else
{
strncpy(pro_name, server->misc3, SERVER_FIELD_SIZE);
}

// sets the active PI Server node where the data for the subsequent
// PI-API calls will be resolved
result = piut_setservernode(server->server_ip);

if (result)
{
ftrace_log(log_tag, "piut_setservernode: can not connect to %s", server->server_ip);
return E_CONNECT_FAILED;
}

if (server->usr_name != NULL && strlen(server->usr_name) > 0)
{
// establishes a user's access to PI System data based on a login to a configured user database
result = piut_login(server->usr_name, server->usr_pwd, &valid);

if (result == 0)
{
ftrace_log(log_tag, "piut_login: connect to %s successful, valid=%d", server->server_ip, valid);
return E_SUCCESS;
}

ferror_log(log_tag, "piut_login: connect to %s failed, ret=%d", server->server_ip, result);
}

//sets the global process name to the passed string
piut_setprocname(pro_name);
result = piut_connect(server->server_ip);

if (result)
{
ferror_log(log_tag, "piut_connect: connect to %s failed, ret=%d", server->server_ip, result);
return E_CONNECT_FAILED;
}
}

return E_SUCCESS;
}

初始化测点信息

连接上 Server 之后,需要根据测点信息,转换成数据库中对应的 id,方便后面的操作

涉及到的 API 函数:

  • pipt_findpoint 转换测点名称为测点号 (必须)
  • pipt_pointtypex 根据测点号查询对应的测点类型
  • pipt_displaydigits 根据测点号查询显示位数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
static int16_t init_pi_tag(pi_tag_t *tag)
{
int32_t result;
int8_t log_tag[MAX_BUFF_SIZE];
strncpy(log_tag, "init_pi_tag", MAX_BUFF_SIZE);

// gets the point number for the given tagname
result = pipt_findpoint(tag->name, &tag->point_id);

if (result)
{
ftrace_log(log_tag, "fetch point[%s] id failed.", tag->name);
tag->stat = NOT_EXIST;
return FALSE;
}

// gets the data type code for the passed point number
result = pipt_pointtypex(tag->point_id, &tag->pt_typex);

if (result)
{
ftrace_log(log_tag, "fetch point[%s] typex failed.", tag->name);
tag->stat = INVALID;
return FALSE;
}

// gets the display digits attribute for the passed point number
result = pipt_displaydigits(tag->point_id, &tag->display_prec);

if (result)
{
ftrace_log(log_tag, "fetch point[%s] display digits failed.", tag->name);
tag->display_prec = -5;
}

tag->stat = NORMAL;
tag->rval = (float64_t) 0.0;
tag->istat = 0;
tag->ival = 0;
tag->flag = 0;

ftrace_log(log_tag, "name:%s, id:%d, dis_prec: %d,type: %d", tag->name, tag->point_id, tag->display_prec, (int32_t)tag->pt_typex);

switch (tag->pt_typex)
{
case PI_Type_PIstring:
case PI_Type_blob:
case PI_Type_PItimestamp:
if (tag->bsize == 0)
{
/* Skip allocation if a subsequent run. */
if ((tag->bval = (void *)malloc(BVALUE_BUFF)) == NULL)
{
error_log(log_tag, "malloc bval failed.");
destory();
return E_MALLOC_FAILED;
}
}

tag->bsize = (tag->bsize > BVALUE_BUFF - 1) ? tag->bsize : BVALUE_BUFF - 1;
memset(tag->bval, 0, (size_t)(tag->bsize + 1));
break;

case PI_Type_int16:
case PI_Type_int32:
tag->bsize = 0;
break;

case PI_Type_digital:
tag->bsize = 0;
break;

default:/* floats, PI2 */
tag->bsize = 0;
break;
} /* End switch */

return TRUE;
}

查询实时数据

从快照中查询数据库,可以通过 pisn_getsnapshot 或者 pisn_getsnapshotx 查询,具体可查考 API 文档。

注: pisn_getsnapshot 获取的时间只到秒级,如果对时间精度要求比较高,需要使用 pisn_getsnapshotx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int16_t getsnapshot()
{
// init parameters etc.
// ...

for (index = 0; index < ptbl_data->point_size; index++, tag++)
{
// check server connection etc
// ...
tag->rval = 0;
tag->istat = 0;

result = pisn_getsnapshot(tag->point_id, &tag->rval, &tag->istat, &tag->time);

if (result == 0)
{
ftrace_log(log_tag, "%s[0x%p] pisn_getsnapshot, rval=%f,ival=%d,time=%d", tag->name, tag, tag->rval, tag->istat, tag->time);
}
else if (result == -1)
{
tag->stat = NOT_EXIST;
ftrace_log(log_tag, "%s pisn_getsnapshot not exist, result=%d.", tag->name, result);
}
else
{
tag->stat = INVALID;
ftrace_log(log_tag, "%s pisn_getsnapshot failed, result=%d.", tag->name, result);
}
}

return TRUE;
}

—EOF—

0%