在物联网产品运营的过程中,产品所处的环境非常复杂,各种无线信号相互干扰,
人为的干预切换设备的信道效果甚微,并且面对大量设备时也力不从心,可以综合环境因素让设备开机或定时自动选择当前最优信道。
/**
create by iversondeng168
*/
#include <sys/time.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <memory.h>
#include <signal.h>
#define UI8 unsigned char
#define I8 char
#define UI32 unsigned int
#define I32 int
//本地网卡mac地址
#define READ_MACADDR "cat /sys/devices/platform/ar934x_wmac/ieee80211/phy0/macaddress"
//使用iwinfo命令搜索附近WiFi信息
#define SCAN_WIFI "iwinfo wlan0 scan"
//国内wifi 5.8G可用频点
static const int chan_arrays_support[] =
{
36,40,44,48,
149,153,157,161,165
};
#define CHANNEL_SUPPORT_SIZE (sizeof(chan_arrays_support) / sizeof(int))
//使用管道派生子进程执行命令
I8* cmd_system(const I8* command)
{
I8* result = "";
FILE *fpRead;
fpRead = popen(command, "r");
I8 buf[1024];
memset(buf,'\0',sizeof(buf));
while(fgets(buf,1024-1,fpRead)!=NULL)
{
result = buf;
}
if(fpRead!=NULL)
pclose(fpRead);
return result;
}
//十六进制字符转十进制
I32 hex_char_to_int(I8 in)
{
if(in >= '0' && in <= '9')
return in - '0';
if(in >= 'a' && in <= 'f')
return (in - 'a') + 10;
if(in >= 'A' && in <= 'F')
return (in - 'A') + 10;
return 0;
}
//在字串符中找出子字符串并返回起始位置
I32 find_substring(const char *pSrc, const char *pDst)
{
int i, j;
for (i=0; pSrc[i]!='\0'; i++)
{
if(pSrc[i]!=pDst[0])
continue;
j = 0;
while(pDst[j]!='\0' && pSrc[i+j]!='\0')
{
j++;
if(pDst[j]!=pSrc[i+j])
break;
}
if(pDst[j]=='\0')
return i;
}
return -1;
}
//使用uci命令指定设置具体信道
static void chan_switch(int is_effect,int chan)
{
UI8 randval;
I8*retpt;
UI8 i;
UI8 is_support;
I8 cmds[128];
memset(cmds,0,128);
if(chan)
{
is_support = 0;
for(i=0;i < CHANNEL_SUPPORT_SIZE;i++)
{
if(chan_arrays_support[i] == chan){
is_support = 1;
break;
}
}
if(!is_support) chan = 0;
}
randval = (!chan) ? chan_arrays_support[rand() % CHANNEL_SUPPORT_SIZE] : chan;
#if 0
///执行选择channel
printf("sel chan is %d\n",randval);
#endif
retpt = cmd_system("uci get wireless.radio0.channel");
if(atoi(retpt) == randval){
#if 0
printf("sel chan is equal to the sys cur channel\n");
#endif
return;
}
sprintf(cmds,"uci set wireless.radio0.channel=%d",randval);
cmd_system(cmds);
cmd_system("uci set wireless.@wifi-iface[0].hidden=1");
cmd_system("uci commit wireless");
if(is_effect){
sleep(1);
cmd_system("wifi down && wifi");
}
}
//使用uci命令提交设置但需要WiFi重启生效
void chan_commit(void)
{
I8*retpt;
I8*tmpt;
UI8 i;
UI32 randval;
UI8 macaddr[6];
I8 cmds[128];
memset(cmds,0,128);
retpt = cmd_system(READ_MACADDR);
tmpt = strtok(retpt,":");
i = 0;
while(tmpt){
macaddr[i++] = hex_char_to_int(tmpt[0]) * 16 + hex_char_to_int(tmpt[1]);//atoi(tmpt);
tmpt = strtok(NULL,":");
}
//让mac来决定channel
randval = macaddr[0] + macaddr[1] + macaddr[2] + macaddr[3] + macaddr[4] + macaddr[5];
#if 0
printf("mac randval=%d\t",randval);
#endif
randval %= CHANNEL_SUPPORT_SIZE;
#if 0
printf("sel channel is %d\n",chan_arrays_support[randval]);
#endif
sprintf(cmds,"uci set wireless.radio0.channel=%d",chan_arrays_support[randval]);
cmd_system(cmds);
cmd_system("uci set wireless.@wifi-iface[0].hidden=1");
cmd_system("uci commit wireless");
}
/**
自动搜索当前环境可用WiFi信道,
信道占用最少,并且信号强度最弱,
则选择该信道设为自身信道.
*/
UI8 chan_auto(void)
{
#define CHAN_CNT_SIZE CHANNEL_SUPPORT_SIZE
#define MAX_BUF_CACHE (1024)
//对应信道统计
I32 chans_cnt[CHAN_CNT_SIZE] = {0};
I32 tmp_chan;
UI8 chans_few = 0;
UI8 tmp[CHAN_CNT_SIZE];
I32 i,j,k;
I8 buf[MAX_BUF_CACHE];
I32 retval;
//对应信道强度最大值统计
I32 chans_signal[CHAN_CNT_SIZE];
I32 tmp_sig;
UI8 tmp2[CHAN_CNT_SIZE];
I32 sig_few = 0;
UI8 tmpval;
FILE *fpRead;
fpRead = popen(SCAN_WIFI, "r");
for(i=0;i < CHAN_CNT_SIZE;i++)
chans_signal[i] = -500;
memset(buf,'\0',sizeof(buf));
while(fgets(buf,MAX_BUF_CACHE - 1,fpRead) != NULL)
{
#if 0
printf("tmp1 buf=%s\n",buf);
#endif
retval = find_substring(buf,"Channel:");
if(retval < 0 ) continue;
tmp_chan = atoi(buf + retval + 8);
if(fgets(buf,MAX_BUF_CACHE - 1,fpRead) == NULL) continue;
#if 0
printf("tmp2 buf=%s\n",buf);
#endif
retval = find_substring(buf,"Signal:");
if(retval < 0) continue;
tmp_sig = atoi(buf + retval + 8);
#if 0
printf("tmp_sig=%d\n",tmp_sig);
#endif
#if 0
printf("tmp_chan=%d\ttmp_sig=%d\n",tmp_chan,tmp_sig);
#endif
switch(tmp_chan)
{
case 36:
chans_cnt[0]++;
if(chans_signal[0] < tmp_sig)
chans_signal[0] = tmp_sig;
break;
case 40:
chans_cnt[1]++;
if(chans_signal[1] < tmp_sig)
chans_signal[1] = tmp_sig;
break;
case 44:
chans_cnt[2]++;
if(chans_signal[2] < tmp_sig)
chans_signal[2] = tmp_sig;
break;
case 48:
chans_cnt[3]++;
if(chans_signal[3] < tmp_sig)
chans_signal[3] = tmp_sig;
break;
case 149:
chans_cnt[4]++;
if(chans_signal[4] < tmp_sig)
chans_signal[4] = tmp_sig;
break;
case 153:
chans_cnt[5]++;
if(chans_signal[5] < tmp_sig)
chans_signal[5] = tmp_sig;
break;
case 157:
chans_cnt[6]++;
if(chans_signal[6] < tmp_sig)
chans_signal[6] = tmp_sig;
break;
case 161:
chans_cnt[7]++;
if(chans_signal[7] < tmp_sig)
chans_signal[7] = tmp_sig;
break;
case 165:
chans_cnt[8]++;
if(chans_signal[8] < tmp_sig)
chans_signal[8] = tmp_sig;
break;
}
}
if(fpRead!=NULL)
pclose(fpRead);
#if 0
for(i=0;i < CHAN_CNT_SIZE;i++)
{
printf("channel %d=%d\t maxsig=%d\n",chan_arrays_support[i],chans_cnt[i],chans_signal[i]);
}
#endif
//最少占用信道统计
chans_few = chans_cnt[0];
for(i=0;i < CHAN_CNT_SIZE;i++)
{
if(chans_few > chans_cnt[i]){
chans_few = chans_cnt[i];
}
}
for(i=0,j=0;i < CHAN_CNT_SIZE;i++)
{
if(chans_cnt[i] == chans_few){
tmp[j++] = i;
}
}
//最少占用信道中信号强度最弱统计
sig_few = chans_signal[0];
for(i=0;i < j;i++)
{
tmpval = tmp[i];
if(sig_few > chans_signal[tmpval])
sig_few = chans_signal[tmpval];
}
for(i=0,k=0;i < j;i++)
{
tmpval = tmp[i];
if(chans_signal[tmpval] == sig_few)
tmp2[k++] = tmpval;
}
return chan_arrays_support[tmp2[rand() % k]];
}
I32 main(I32 argc,I8*argv[])
{
UI8 is_effect = 1;
UI8 chan = 0;
srand(time(NULL));
if(argc > 1)
{
//随机信道只提交下次生效
if(!strcmp("commit",argv[1]) ||
!strcmp("COMMIT",argv[1]))
{
chan_commit();
return 0;
}
//自动选择最优信道
else if(!strcmp("auto",argv[1]) ||
!strcmp("AUTO",argv[1]))
{
is_effect = 0;
chan = chan_auto();
}
//指定具体信道
else if(!strcmp("-c",argv[1]) ||
!strcmp("-C",argv[1]))
{
chan = atoi(argv[2]);
}
}
else
{
sleep(1);
}
chan_switch(is_effect,chan);
return 0;
}
执行交叉编译
GCC=/home/openwrt-master/staging_dir/toolchain-mips_74kc_gcc-5.3.0_musl-1.1.16/bin/mips-openwrt-linux-gcc
$GCC chan_switch.c -o chan_switch -O2 -w