【DWM1000】 code 解密1一 去掉Main 函数多余内容
蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛
正文:
室内定位兴起,DWM1000 作为超宽带UWB的代表,在国内用的越来越多,但是可见资料非常少。 一方面是官方代码写的实在有点太差,另一方面是现在国内普及者将自己的代码当作是商业机密,当作是卖点,很少出来分享解析的。
我计划花一段时间来梳理DWM1000 代码,之前稍微接触过一点,感觉还能理解DWM1000 一点思路。 放在这里供大家参考。
作为穷人,目前我淘到一块DWM1000 模块,与我老旧的STM32 还没有互连,也就是说,还没有调试。这里的代码主要是分析思路,难免有误,请大家甄别参考。
拿到DWM1000 定位代码后发现需要CoCox编译,其实这个编译环境我试了试还是挺好的,免费的东西做成这样已经非常棒了,没有必要换成Keil 了。 另外我分析代码使用了source insight,我本人更偏向用vim 。 推荐大家用SI,有兴趣用vim。
好了,第一节,我想主要是清理一下Main 函数,因为太多LCD相关的,我们分析code,假定没有液晶,也不考虑LED以及USB把相关代码先全部注释掉。
int main(void)
{
int i = 0;
int toggle = 1;
double range_result = 0;
double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs peripherals_init(); spi_peripheral_init(); /* Sleep(1000); //wait for LCD to power on initLCD(); memset(dataseq, 0, LCD_BUFF_LEN);
memcpy(dataseq, (const uint8 *) "DECAWAVE ", 16);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(dataseq, (const uint8 *) SOFTWARE_VER_STRING, 16); // Also set at line #26 (Should make this from single value !!!)
writetoLCD( 16, 1, dataseq); //send some data Sleep(1000);*/
/*
#ifdef USB_SUPPORT
// enable the USB functionality
usb_init();
Sleep(1000);
#endif*/ s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2
| is_switch_on(TA_SW1_3) << 2
| is_switch_on(TA_SW1_4) << 3
| is_switch_on(TA_SW1_5) << 4
| is_switch_on(TA_SW1_6) << 5
| is_switch_on(TA_SW1_7) << 6
| is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device //test EVB1000 - used in EVK1000 production
if((is_button_low(0) == S1_SWITCH_ON) && (is_switch_on(TA_SW1_8) == S1_SWITCH_ON)) //using BOOT1 switch for test
{
test_application_run(); //does not return....
}
else
if(is_switch_on(TA_SW1_3) == S1_SWITCH_OFF)
{
/* int j = 1000000;
uint8 command; memset(dataseq, 0, LCD_BUFF_LEN); while(j--);
//command = 0x1 ; //clear screen
//writetoLCD( 1, 0, &command);
command = 0x2 ; //return cursor home
writetoLCD( 1, 0, &command); memcpy(dataseq, (const uint8 *) "DECAWAVE ", 12);
writetoLCD( 40, 1, dataseq); //send some data
#ifdef USB_SUPPORT //this is set in the port.h file
memcpy(dataseq, (const uint8 *) "USB to SPI ", 12);
#else
#endif
writetoLCD( 16, 1, dataseq); //send some data j = 1000000; while(j--); command = 0x2 ; //return cursor home
writetoLCD( 1, 0, &command);*/
/*
#ifdef USB_SUPPORT //this is set in the port.h file
// enable the USB functionality
//usb_init(); NVIC_DisableDECAIRQ(); // Do nothing in foreground -- allow USB application to run, I guess on the basis of USB interrupts?
while (1) // loop forever
{
usb_run();
}
#endif*/
return 1;
}
else //run DecaRanging application
{
/* uint8 dataseq[LCD_BUFF_LEN];
uint8 command = 0x0; command = 0x2 ; //return cursor home
writetoLCD( 1, 0, &command);
memset(dataseq, ' ', LCD_BUFF_LEN);
memcpy(dataseq, (const uint8 *) "DECAWAVE RANGE", 15);
writetoLCD( 15, 1, dataseq); //send some data led_off(LED_ALL); #ifdef USB_SUPPORT //this is set in the port.h file
usb_printconfig(16, (uint8 *)SOFTWARE_VER_STRING, s1switch);
#endif*/ if(inittestapplication(s1switch) == (uint32)-1)
{
/* led_on(LED_ALL); //to display error....
dataseq[0] = 0x2 ; //return cursor home
writetoLCD( 1, 0, &dataseq[0]);
memset(dataseq, ' ', LCD_BUFF_LEN);
memcpy(dataseq, (const uint8 *) "ERROR ", 12);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(dataseq, (const uint8 *) " INIT FAIL ", 12);
writetoLCD( 40, 1, dataseq); //send some data*/
return 0; //error
} //sleep for 5 seconds displaying "Decawave"
/* i=30;
while(i--)
{
if (i & 1) led_off(LED_ALL);
else led_on(LED_ALL); Sleep(200);
}
i = 0;
led_off(LED_ALL);
command = 0x2 ; //return cursor home
writetoLCD( 1, 0, &command); memset(dataseq, ' ', LCD_BUFF_LEN);*/ if(s1switch & SWS1_ANC_MODE)
{
instance_mode = ANCHOR; /led_on(LED_PC6);
}/
else
{
instance_mode = TAG;
// led_on(LED_PC7);
} /*if(instance_mode == TAG)
{
//if TA_SW1_2 is on use fast ranging (fast 2wr)
if(is_button_low(0) == S1_SWITCH_ON)
{
memcpy(&dataseq[2], (const uint8 *) " Fast Tag ", 12);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(&dataseq[2], (const uint8 *) " Ranging ", 12);
writetoLCD( 16, 1, dataseq); //send some data
}
else
{
memcpy(&dataseq[2], (const uint8 *) " TAG BLINK ", 12); writetoLCD( 40, 1, dataseq); //send some data
sprintf((char*)&dataseq[0], "%llX", instance_get_addr());
writetoLCD( 16, 1, dataseq); //send some data
}
}
else
{
memcpy(&dataseq[2], (const uint8 *) " AWAITING ", 12);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(&dataseq[2], (const uint8 *) " POLL ", 12);
writetoLCD( 16, 1, dataseq); //send some data
} command = 0x2 ; //return cursor home
writetoLCD( 1, 0, &command);*/
}
#if (DWINTERRUPT_EN == 1)//CN:define1
port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
#endif /* memset(dataseq, ' ', LCD_BUFF_LEN);
memset(dataseq1, ' ', LCD_BUFF_LEN); #ifdef USART_SUPPORT
printf2(" %s\n", SOFTWARE_VER_STRING);
#endif*/ // main loop
while(1)
{
/*
#if (DWINTERRUPT_EN == 0)
process_deca_irq(); //poll DW1000 IRQ line when using polling of interrupt line
#endif*/
instance_run(); //if delayed TX scheduled but did not happen after expected time then it has failed... (has to be < slot period)
//if anchor just go into RX and wait for next message from tags/anchors
//if tag handle as a timeout
if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms))
{
instance_data[0].wait4ack = 0; if(instance_mode == TAG)
{
inst_processrxtimeout(&instance_data[0]);
}
else //if(instance_mode == ANCHOR)
{
dwt_forcetrxoff(); //this will clear all events
//enable the RX
instance_data[0].testAppState = TA_RXE_WAIT ;
}
instance_data[0].monitor = 0;
} if(instancenewrange())
{
int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw;
ranging = 1;
//send the new range information to LCD and/or USB
range_result = instance_get_idist();
avg_result = instance_get_adist();
//set_rangeresult(range_result);
/* dataseq[0] = 0x2 ; //return cursor home
writetoLCD( 1, 0, dataseq); memset(dataseq, ' ', LCD_BUFF_LEN);
memset(dataseq1, ' ', LCD_BUFF_LEN);
sprintf((char*)&dataseq[1], "LAST: %4.2f m", range_result);
writetoLCD( 40, 1, dataseq); //send some data sprintf((char*)&dataseq1[1], "AVG8: %4.2f m", avg_result); writetoLCD( 16, 1, dataseq1); //send some data*/ l = instance_get_lcount();
//txl = instance_get_txl();
//rxl = instance_get_rxl();
aaddr = instancenewrangeancadd();
taddr = instancenewrangetagadd();
txa = instancetxantdly();
rxa = instancerxantdly();
rng = (int) (range_result*1000);
rng_raw = (int) (instance_get_idistraw()*1000); /* if(instance_mode == TAG)
{
//n = sprintf((char*)&dataseq[0], "ia%04x t%04x %04x %04x %04x %04x %04x %02x %02x t", aaddr, taddr, rng, rng_raw, l, txa, rxa, txl, rxl);
n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x t", aaddr, taddr, rng, rng_raw, l, txa, rxa);
}
else
{
//n = sprintf((char*)&dataseq[0], "ia%04x t%04x %04x %04x %04x %04x %04x %02x %02x a", aaddr, taddr, rng, rng_raw, l, txa, rxa, txl, rxl);
//n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x %2.2f a", aaddr, taddr, rng, rng_raw, l, txa, rxa, instance_data[0].clockOffset);
n = sprintf((char*)&dataseq[0], "ia%04x t%04x %08x %08x %04x %04x %04x a", aaddr, taddr, rng, rng_raw, l, txa, rxa);
}
#ifdef USB_SUPPORT //this is set in the port.h file
send_usbmessage(&dataseq[0], n);
#endif*/
/*
#ifdef USART_SUPPORT
{ //printf2("R= %i mm\r\n",rng);
printf2("R= %-3.2f m\r\n",range_result);
}
#endif*/
}
/*
#ifdef USART_SUPPORT
{
int nrm = 0;
if(nrm = instancenorange())
{
if(nrm == 1)
{
printf2("I= No Response\r\n");
}
else if(nrm == 2)
{
printf2("I= No Report\r\n");
}
else if(nrm == 3)
{
printf2("I= No Final\r\n");
}
}
}
#endif*/ if(ranging == 0)
{
if(instance_mode != ANCHOR)
{
if(instancesleeping())
{
//dataseq[0] = 0x2 ; //return cursor home
// writetoLCD( 1, 0, dataseq);
if(toggle)
{
/* toggle = 0;
memcpy(&dataseq[0], (const uint8 *) " AWAITING ", 16);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(&dataseq[0], (const uint8 *) " RESPONSE ", 16);
writetoLCD( 16, 1, dataseq); //send some data*/
}
else
{
/* toggle = 1;
memcpy(&dataseq[2], (const uint8 *) " TAG BLINK ", 16); writetoLCD( 40, 1, dataseq); //send some data
sprintf((char*)&dataseq[0], "%llX", instance_get_addr());
writetoLCD( 16, 1, dataseq); //send some data*/
}
} if(instanceanchorwaiting() == 2)
{
ranging = 1;
/* dataseq[0] = 0x2 ; //return cursor home
writetoLCD( 1, 0, dataseq);
memcpy(&dataseq[0], (const uint8 *) " RANGING WITH", 16);
writetoLCD( 40, 1, dataseq); //send some data
sprintf((char*)&dataseq[0], "%016llX", instance_get_anchaddr());
writetoLCD( 16, 1, dataseq); //send some data*/
}
}
else //if(instance_mode == ANCHOR)
{
if(instanceanchorwaiting())
{
/* toggle+=2; if(toggle > 300000)
{
dataseq[0] = 0x2 ; //return cursor home
writetoLCD( 1, 0, dataseq);
if(toggle & 0x1)
{
toggle = 0;
memcpy(&dataseq[0], (const uint8 *) " AWAITING ", 16);
writetoLCD( 40, 1, dataseq); //send some data
memcpy(&dataseq[0], (const uint8 *) " POLL ", 16);
writetoLCD( 16, 1, dataseq); //send some data
}
else
{
toggle = 1;
memcpy(&dataseq[0], (const uint8 *) " DISCOVERY MODE ", 16);
writetoLCD( 40, 1, dataseq); //send some data
sprintf((char*)&dataseq[0], "%llX", instance_get_addr());
writetoLCD( 16, 1, dataseq); //send some data
}
}*/ }
else if(instanceanchorwaiting() == 2)
{
/* dataseq[0] = 0x2 ; //return cursor home
writetoLCD( 1, 0, dataseq);
memcpy(&dataseq[0], (const uint8 *) " RANGING WITH", 16);
writetoLCD( 40, 1, dataseq); //send some data
sprintf((char*)&dataseq[0], "%llX", instance_get_tagaddr());
writetoLCD( 16, 1, dataseq); //send some data*/
}
}
} /*
#ifdef USB_SUPPORT //this is set in the port.h file
usb_run();
#endif*/
} return 0;
}
上面代码不用看,如果你看了,恭喜你,帮我找一下看我注释掉的代码是否有问题, 我把注释掉的直接先删掉吧,虽然不是处女座,但是我看code 非常有洁癖的。
int main(void)
{
int i = 0;
int toggle = 1;
double range_result = 0;
double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs
peripherals_init();
spi_peripheral_init(); s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2
| is_switch_on(TA_SW1_3) << 2
| is_switch_on(TA_SW1_4) << 3
| is_switch_on(TA_SW1_5) << 4
| is_switch_on(TA_SW1_6) << 5
| is_switch_on(TA_SW1_7) << 6
| is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device
//test EVB1000 - used in EVK1000 production
if((is_button_low(0) == S1_SWITCH_ON) && (is_switch_on(TA_SW1_8) == S1_SWITCH_ON)) //using BOOT1 switch for test
{
test_application_run(); //does not return....
}
else
if(is_switch_on(TA_SW1_3) == S1_SWITCH_OFF)
{
return 1;
}
else //run DecaRanging application
{
if(inittestapplication(s1switch) == (uint32)-1)
{
return 0; //error
} if(s1switch & SWS1_ANC_MODE)
{
instance_mode = ANCHOR; /led_on(LED_PC6);
}/
else
{
instance_mode = TAG; }
}
#if (DWINTERRUPT_EN == 1)//CN:define1
port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
#endif
// main loop
while(1)
{
instance_run();
if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms))
{
instance_data[0].wait4ack = 0; if(instance_mode == TAG)
{
inst_processrxtimeout(&instance_data[0]);
}
else //if(instance_mode == ANCHOR)
{
dwt_forcetrxoff(); //this will clear all events
//enable the RX
instance_data[0].testAppState = TA_RXE_WAIT ;
}
instance_data[0].monitor = 0;
}
if(instancenewrange())
{
int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw;
ranging = 1;
//send the new range information to LCD and/or USB
range_result = instance_get_idist();
avg_result = instance_get_adist();
l = instance_get_lcount();
//txl = instance_get_txl();
//rxl = instance_get_rxl();
aaddr = instancenewrangeancadd();
taddr = instancenewrangetagadd();
txa = instancetxantdly();
rxa = instancerxantdly();
rng = (int) (range_result*1000);
rng_raw = (int) (instance_get_idistraw()*1000);
if(ranging == 0)
{
if(instance_mode != ANCHOR)
{
if(instancesleeping())
{
if(toggle)
{
}
else
{
}
}
if(instanceanchorwaiting() == 2)
{
ranging = 1; }
}
else //if(instance_mode == ANCHOR)
{
if(instanceanchorwaiting())
{ }
else if(instanceanchorwaiting() == 2)
{
}
}
} }
return 0;
}
删除注释,一下清爽很多,可能删除了一些有用的code,如果后面分析不同,我们再补回来。
下面再删除一个关于test的东西, Main 函数开始通过按键选择执行,有个test函数还不返回,我们定位不执行这部分,再次删除。
删除函数: test_application_run(); //does not return....
int main(void)
{
int i = 0;
int toggle = 1;
double range_result = 0;
double avg_result = 0; led_off(LED_ALL); //turn off all the LEDs
peripherals_init();
spi_peripheral_init(); s1switch = is_button_low(0) << 1 // is_switch_on(TA_SW1_2) << 2
| is_switch_on(TA_SW1_3) << 2
| is_switch_on(TA_SW1_4) << 3
| is_switch_on(TA_SW1_5) << 4
| is_switch_on(TA_SW1_6) << 5
| is_switch_on(TA_SW1_7) << 6
| is_switch_on(TA_SW1_8) << 7; port_DisableEXT_IRQ(); //disable ScenSor IRQ until we configure the device
else //run DecaRanging application
{
if(inittestapplication(s1switch) == (uint32)-1)
{
return 0; //error
} if(s1switch & SWS1_ANC_MODE)
{
instance_mode = ANCHOR; /led_on(LED_PC6);
}/
else
{
instance_mode = TAG; }
}
#if (DWINTERRUPT_EN == 1)//CN:define1
port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
#endif
// main loop
while(1)
{
instance_run();
if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0].timeofTx) > instance_data[0].finalReplyDelay_ms))
{
instance_data[0].wait4ack = 0; if(instance_mode == TAG)
{
inst_processrxtimeout(&instance_data[0]);
}
else //if(instance_mode == ANCHOR)
{
dwt_forcetrxoff(); //this will clear all events
//enable the RX
instance_data[0].testAppState = TA_RXE_WAIT ;
}
instance_data[0].monitor = 0;
}
if(instancenewrange())
{
int n, l = 0, /*txl = 0, rxl = 0,*/ aaddr, taddr, txa, rxa, rng, rng_raw;
ranging = 1;
//send the new range information to LCD and/or USB
range_result = instance_get_idist();
avg_result = instance_get_adist();
l = instance_get_lcount();
//txl = instance_get_txl();
//rxl = instance_get_rxl();
aaddr = instancenewrangeancadd();
taddr = instancenewrangetagadd();
txa = instancetxantdly();
rxa = instancerxantdly();
rng = (int) (range_result*1000);
rng_raw = (int) (instance_get_idistraw()*1000);
if(ranging == 0)
{
if(instance_mode != ANCHOR)
{
if(instancesleeping())
{
if(toggle)
{
}
else
{
}
}
if(instanceanchorwaiting() == 2)
{
ranging = 1; }
}
else //if(instance_mode == ANCHOR)
{
if(instanceanchorwaiting())
{ }
else if(instanceanchorwaiting() == 2)
{
}
}
} }
return 0;
}
再来看现在代码,直接从else 开始了,直奔主题。
if(inittestapplication(s1switch) == (uint32)-1)
{
return 0; //error
} if(s1switch & SWS1_ANC_MODE)
{
instance_mode = ANCHOR; /led_on(LED_PC6);
}/
else
{
instance_mode = TAG; }
}
#if (DWINTERRUPT_EN == 1)//CN:define1
port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
#endif
// main loop
while(1)
{
instance_run();
上面代码中,红色字体的两个函数是整个定位中非常重要的两个函数。
第一节,就分析到这里,主要是删除多余代码
【DWM1000】 code 解密1一 去掉Main 函数多余内容的更多相关文章
- 【DWM1000】 code 解密5一ACHOR 第一次回家Main 函数
instance_run(); if((instance_data[0].monitor == 1) && ((portGetTickCnt() - instance_data[0]. ...
- 【DWM1000】 code 解密6一TAG 状态机第一步
我们前面分析过,不论ANCHOR 还是TAG,前面变量的初始化基本都是一样的,只是状态机必须明确区分不同的设备类型.我们从开始看TAG.由于初始化TAG的 testAppState一样初始化为TA_I ...
- 【Go入门教程3】流程(if、goto、for、switch)和函数(多个返回值、变参、传值与传指针、defer、函数作为值/类型、Panic和Recover、main函数和init函数、import)
这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和 ...
- Atitit dsl对于数组的处理以及main函数的参数赋值
Atitit dsl对于数组的处理以及main函数的参数赋值 1.1. 词法解析..添加了[] 方括号的解析支持1 1.2. Ast建立.添加了数组参数的支持..使用了递归下降法..getparam ...
- SequoiaDB 系列之五 :源码分析之main函数
好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...
- 为什么需要main函数,及其参数的用法
首先,需要明确main函数是什么? 答:main函数是C语言约定的入口函数 C99标准里面是这样描述的: Program startup The function called at program ...
- C++向main函数传递参数的方法(实例已上传至github)
通常情况下,我们定义的main函数都只有空形参列表: int main(){...} 然而,有时我们确实需要给mian传递实参,一种常见的情况是用户设置一组选项来确定函数所要执行的操作.例如,假定ma ...
- 转:iOS程序main函数之前发生了什么
原文地址:http://blog.sunnyxx.com/2014/08/30/objc-pre-main/ 我是前言 一个iOS app的main()函数位于main.m中,这是我们熟知的程序入口. ...
- C语言编程漫谈——main函数
写在前面 促使我写这篇文章是因为我这几天找了几个一样是大三的同学,与我相同专业相同方向(物联网)的人,除了@小胡同的诗,基本没有什么其他人会现在看起来很简单的编程题目了.问了一下其他同学,他们大部分都 ...
随机推荐
- 原创 《算法》java第四版,标准输入
<算法>学习过程中,在eclipse里调试时,对于官方提供的源码中标准输入的操作,没有搞懂 自己改了一下,直接读取本地测试数据测试数据可在http://algs4.cs.princet ...
- AI-序列化-查-做接口
序列化最终代码(下边的可以不看) from rest_framework.views import APIView from rest_framework import serializers fro ...
- python面向对象三大特性之继承
继承是创建新类的方法,以下是几个概念 父类,基类,超类: 被继承的类 子类,派生类:继承而产出的类 单继承:继承一个父类 多继承:继承多个父类 继承: 什么是什么的关系 父类中没有的属性,在字类中出现 ...
- Java+selenium之WebDriver对浏览器的简单操作(一)
操作浏览器的主要方法都来自 org.openqa.selenium.WebDriver 这个接口 这些方法都是在 org.openqa.selenium.remote.RemoteWebDriver这 ...
- SQL Server常见的操作符
常见的操作符:Sort.Hash Match(聚合).Filter.Compute Scalar等 一:Sort select Shelf from Production.ProductInvento ...
- ubuntu下的“用vim打开中文乱码,用cat打开正常显示”的解决方法
转载 系统环境:ubuntu10.04 vim gvim完全安装 问题:终端下vim中的汉字为乱码,网上搜索了一些解决方案.但是奇怪的是,这些方法都不能实现gvim的菜单和文中汉字,终端vim下的文中 ...
- 【Socket】Java Socket编程基础及深入讲解
Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要讲解Socket的基础编程.Socket用在哪呢,主要用在进程间,网络间通信.本篇比较长,特别做了个目录: 一.Socket通信基 ...
- 【总结】瞬时高并发(秒杀/活动)Redis方案(转)
转载地址:http://bradyzhu.iteye.com/blog/2270698 1,Redis 丰富的数据结构(Data Structures) 字符串(String) Redis字符串能包含 ...
- bzoj2870
题解: 边分治入门题 当然并查集+维护直径更加简单 就是两棵树二合一直径是两颗树上的4个直径两两组合的最大值 查询路径长度你搞个差分查个lca就好了 点分治并不能做这题 分成多个联通块就gg了(点分治 ...
- net core体系-3再次认识net core
1 什么是ASP.NET Core ASP.NET Core 是一个全新的开源.跨平台框架,可以用它来构建基于网络连接的现代云应用程序,比如:Web 应用,IoT(Internet Of Things ...