@Gentlepig
抱歉,我那代码可能写得不太好,也欠缺相关注释。你的理解是对的,rpnbuf储存的就是后缀表达式。
首先建立一个空栈和用来储存后缀表达式的缓冲区,然后遍历整个字符串,根据以下原则做处理:
遇到操作数(这里是x1、x2和x3之类),直接将x后面的字符(如'1'、'2'、'3'等)追加到rpnbuf中。
遇到'(',将其入栈。
遇到')',将栈顶元素依次弹出并追加到rpnbuf中,直到遇到')',然后将'('从栈中弹出。
遇到运算符(这里是||和&&,但是为方便后续处理,储存的时候只储存'|'和'&'):
1、如果栈为空或者栈顶是'(',则直接将当前运算符入栈。。
2、如果该运算符的优先级高于栈顶运算符,则直接将其入栈。
3、如果该运算符的优先级低于或等于栈顶运算符,则将栈顶运算符弹出并追加到rpnbuf中,然后将当前运算符入栈。
由于本案例中只涉及'||'和'&&'这两个运算符,并且它们的优先级是相等的,因此我的代码里并没有优先级判定这部分代码,也就是说,在上面的”遇到运算符“的处理中,只处理了第1点和第3点。
对于rpnbuf的处理:
先建立一个空栈,然后按顺序遍历后缀表达式(即rpnbuf)的每个字符:
遇到操作数时,将其入栈。
遇到操作符时,从栈顶依次取出2个操作数进行计算,并将计算结果重新入栈。
遍历完后缀表达式后,栈中的唯一元素就是最终的计算结果。
另外,因为本案例中,表达式中的操作数是个不确定的值,需要从芯片引脚获取电平来确定实际的值,所以在处理rpnbuf操作数的时候,需要标记这个操作数到底是中间运算结果还是需要从芯片引脚读取。我的代码只做了个简单的处理,就是如果是中间运算结果,那就位或0x80(即最高位置1),如果直接是'1'~'8',那就从芯片引脚中取电平来确定这个值是0还是1,根据最高位来判定是直接计算还是从芯片引脚读取电平。
不知道我说明白了没有,希望能对你有用。关于中缀表达式转后缀表达式的方法,网上也有其他相关资料可以参考一下。
移植这个函数,返回指定引脚电平:
uint8_t get_pin_value(char pin)
{
switch (pin) {
case '1': return 1;
case '2': return 0;
case '3': return 1;
case '4': return 0;
case '5': return 1;
case '6': return 0;
case '7': return 0;
case '8': return 0;
default: break;
}
return 0;
}
计算表达式算法:
#include <stdint.h>
#include <stdbool.h>
#define STACK_SIZE 64
static char stkbuf[STACK_SIZE];
static int stk_top_idx = -1;
static int stk_size(void)
{
return stk_top_idx + 1;
}
static char stk_top(void)
{
if (stk_top_idx < 0)
return 0;
return stkbuf[stk_top_idx];
}
static void stk_push(char chr)
{
if (stk_top_idx >= (STACK_SIZE - 1))
return;
stkbuf[++stk_top_idx] = chr;
}
static void stk_pop(void)
{
if (stk_top_idx >= 0)
stk_top_idx--;
}
static void stk_clear(void)
{
stk_top_idx = -1;
}
#define RPN_BUF_SIZE 64
static char rpnbuf[RPN_BUF_SIZE];
static int rpn_cnt = 0;
bool reverse_polish_notatio_append_chr(char chr)
{
bool ok;
if (chr == '(') {
stk_push(chr);
}
else if (chr == ')') {
ok = false;
while (stk_size() > 0) {
chr = stk_top();
stk_pop();
if (chr == '(') {
ok = true;
break;
}
rpnbuf[rpn_cnt++] = chr;
}
if (!ok)
return false;
}
else if (chr == '|' || chr == '&') {
if (stk_size() > 0) {
char chr_top = stk_top();
if (chr_top != '(') {
stk_pop();
rpnbuf[rpn_cnt++] = chr_top;
}
stk_push(chr);
}
else {
stk_push(chr);
}
}
else if ((chr >= '1') && (chr <= '8')) {
rpnbuf[rpn_cnt++] = chr;
}
else {
return false;
}
return true;
}
bool run_exp(const char *exp, uint8_t *result)
{
int i;
char chr, v1, v2, v;
uint8_t flag_result = 0x80;
rpn_cnt = 0;
stk_clear();
while ((chr = exp[0])) {
switch (chr) {
case 'x':
chr = exp[1];
if ((chr < '1') && (chr > '8'))
return false;
if (!reverse_polish_notatio_append_chr(chr))
return false;
exp += 2;
break;
case '&':
case '|':
if (exp[1] != chr)
return false;
if (!reverse_polish_notatio_append_chr(chr))
return false;
exp += 2;
break;
case '(':
case ')':
if (!reverse_polish_notatio_append_chr(chr))
return false;
exp++;
break;
case ' ':
exp++;
break;
default:
break;
}
}
stk_clear();
for (i = 0; i < (int)rpn_cnt; i++) {
chr = rpnbuf[i];
if (chr >= '1' && chr <= '8') {
stk_push(chr);
}
else if ((chr == '|') || (chr == '&')) {
if (stk_size() <= 0)
return false;
v2 = stk_top();
stk_pop();
if (stk_size() <= 0)
return false;
v1 = stk_top();
stk_pop();
if ((v2 & flag_result) == 0)
v2 = get_pin_value(v2);
if ((v1 & flag_result) == 0)
v1 = get_pin_value(v1);
v1 &= ~flag_result;
v2 &= ~flag_result;
v = (chr == '|') ? v1 || v2 : v1 && v2;
stk_push(flag_result | v);
}
}
if (stk_size() == 1) {
*result = (stk_top() & 0x7f);
return true;
}
return false;
}
测试:
int main(int argc, char *argv[])
{
const char *exp = "(((x1 || x2 && x3)) && (x4 || x5))";
uint8_t result;
if (run_exp(exp, &result)) {
printf("rst: %d\n", result);
}
else {
printf("calc fail\n");
}
return 0;
}
输出结果:
rst: 1
使用的linux内核
git clone https://github.com/Lichee-Pi/linux.git --depth=1 -b nano-4.14-exp
1、修改 include/dt-bindings/clock/suniv-ccu.h 文件
在
#define CLK_AVS 66
下面添加
#define CLK_CIR 67
2、修改 drivers/clk/sunxi-ng/ccu-suniv.h 文件
把
#define CLK_NUMBER (CLK_AVS + 1)
改成
#define CLK_NUMBER (CLK_CIR + 1)
3、修改 drivers/clk/sunxi-ng/ccu-suniv.c 文件
添加如下定义
static const char * const cir_parents[] = { "losc", "osc24M" };
static SUNXI_CCU_MP_WITH_MUX_GATE(cir_clk, "ir", cir_parents, 0x0b8,
0, 4, /* M */
16, 2, /* P */
24, 2, /* mux */
BIT(31), /* gate */
0);
在 suniv_ccu_clks[] 追加一项 &cir_clk.common,
static struct ccu_common *suniv_ccu_clks[] = {
......
&avs_clk.common,
&cir_clk.common, // 添加这一行
};
在 suniv_hw_clks 追加一项 &cir_clk.common,
static struct clk_hw_onecell_data suniv_hw_clks = {
.hws = {
......
[CLK_AVS] = &avs_clk.common.hw,
[CLK_CIR] = &cir_clk.common.hw, // 添加这一行
},
.num = CLK_NUMBER,
};
4、修改 suniv.dtsi 文件
添加
cir_pins_a: cir@0 {
pins = "PE11";
function = "ir";
allwinner,muxsel = <4>;
allwinner,drive = <1>;
allwinner,pull = <0>;
};
cir: cir@1C22C00{
compatible = "allwinner,sun4i-a10-ir";
reg = <0x01C22C00 0x400>;
interrupts = <6>;
clocks = <&ccu CLK_BUS_IR>, <&ccu CLK_CIR>;
clock-names = "apb", "ir";
resets = <&ccu RST_BUS_IR>;
pinctrl-names = "default";
pinctrl-0 = <&cir_pins_a>;
status = "okay";
};
5、make ARCH=arm menuconfig打开linux内核配置如下选项:
Device Drivers --->
<*> Remote Controller support --->
[*] Remote controller decoders --->
<*> Enable IR raw decoder for the NEC protocol
<*> Enable IR raw decoder for the RC-5 protocol
<*> Enable IR raw decoder for the RC6 protocol
<*> Enable IR raw decoder for the JVC protocol
<*> Enable IR raw decoder for the Sony protocol
<*> Enable IR raw decoder for the Sanyo protocol
<*> Enable IR raw decoder for the Sharp protocol
<*> Enable IR raw decoder for the MCE keyboard/mouse protocol
<*> Enable IR raw decoder for the XMP protocol
[*] Remote Controller devices --->
<*> SUNXI IR remote control
6、重新编译内核,系统启动时若IR初始化正常,将打印如下IR相关的日志信息
[ 0.955993] IR NEC protocol handler initialized
[ 0.960649] IR RC5(x/sz) protocol handler initialized
[ 0.965699] IR RC6 protocol handler initialized
[ 0.970268] IR JVC protocol handler initialized
[ 0.974788] IR Sony protocol handler initialized
[ 0.979426] IR SANYO protocol handler initialized
[ 0.984121] IR Sharp protocol handler initialized
[ 0.988844] IR MCE Keyboard/mouse protocol handler initialized
[ 0.994660] IR XMP protocol handler initialized
[ 1.000837] Registered IR keymap rc-empty
[ 1.005153] rc rc0: sunxi-ir as /devices/platform/soc/1c22c00.cir/rc/rc0
[ 1.012409] input: sunxi-ir as /devices/platform/soc/1c22c00.cir/rc/rc0/input2
[ 1.021028] input: MCE IR Keyboard/Mouse (sunxi-ir) as /devices/virtual/input/input3
[ 1.029990] sunxi-ir 1c22c00.cir: initialized sunXi IR driver
7、查看红外接收支持的解码协议
# cat /sys/class/rc/rc0/protocols
rc-5 nec rc-6 jvc sony rc-5-sz sanyo sharp mce_kbd xmp
8、使用 NEC 协议
# echo nec > /sys/class/rc/rc0/protocols
# cat /sys/class/rc/rc0/protocols
rc-5 [nec] rc-6 jvc sony rc-5-sz sanyo sharp mce_kbd xmp
9、查看输入设备
# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="1c24800.rtp"
P: Phys=sun4i_ts/input0
S: Sysfs=/devices/platform/soc/1c24800.rtp/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=b
B: KEY=400 0 0 0 0 0 0 0 0 0 0
B: ABS=3
I: Bus=0019 Vendor=0000 Product=0000 Version=0000
N: Name="rotary@0"
P: Phys=
S: Sysfs=/devices/platform/rotary@0/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=5
B: REL=1
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="sunxi-ir"
P: Phys=sunxi-ir/input0
S: Sysfs=/devices/platform/soc/1c22c00.cir/rc/rc0/input2
U: Uniq=
H: Handlers=kbd event2
B: PROP=0
B: EV=100013
B: KEY=1000000 0 0 0 0
B: MSC=10
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="MCE IR Keyboard/Mouse (sunxi-ir)"
P: Phys=/input0
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=kbd event3
B: PROP=0
B: EV=100017
B: KEY=30000 0 7 ff87207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: REL=3
B: MSC=10
10、测试红外接收
从上面输入设备可以看到,ir使用event2,通过使用evtest测试,按下遥控器时,evtest输出如下按键信息,输出的value值与逻辑分析仪采集的数据一致,说明按键码接收正常。
# evtest /dev/input/event2
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "sunxi-ir"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 152 (KEY_SCREENLOCK)
Event type 4 (EV_MSC)
Event code 4 (MSC_SCAN)
Key repeat handling:
Repeat type 20 (EV_REP)
Repeat code 0 (REP_DELAY)
Value 500
Repeat code 1 (REP_PERIOD)
Value 125
Testing ... (interrupt to exit)
Event: time 68.119608, type 4 (EV_MSC), code 4 (MSC_SCAN), value 114
Event: time 68.119608, -------------- SYN_REPORT ------------
Event: time 68.171084, type 4 (EV_MSC), code 4 (MSC_SCAN), value 114
Event: time 68.171084, -------------- SYN_REPORT ------------
ifconfig
eth0 Link encap:Ethernet HWaddr 02:00:4D:F1:C2:6B
inet addr:192.168.1.15 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:118 errors:0 dropped:0 overruns:0 frame:0
TX packets:107 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:18941 (18.4 KiB) TX bytes:23953 (23.3 KiB)
Interrupt:35向192.168.1.255:20000 ,或者255.255.255.255:20000 收不到,向192.168.1.15:20000可以收到,是网络协议还是驱动有问题?
发送端套接字设置了SO_BROADCAST标志没有?不然发不出广播包。另外,还有可能是广播包被VMware的虚拟网卡吃掉了,把VMware开头的网卡禁掉再试试看