MTK平台下Battery驱动分析及充电流程_stoic163的博客-程序员宝宝_mtk充电驱动

技术标签: Linux驱动总结  手机充电总结  Android总结  MTK平台驱动学习  

转自:http://blog.csdn.NET/baidu_34021173/article/details/51105223

主要涉及代码:

Kernel:

kernel-3.10\drivers\power\mediatek\

kernel-3.10\drivers\misc\mediatek\mach\mt6580\<project_name>\power\


MTK Battery框架结构图


通过上层通过读取创建一系列的设备节点获取电池相关的状态信息




Android电源管理系统
/sys/class/power_supply/ac/online //AC 电源连接状态 交流电 即电源插座
/sys/class/power_supply/usb/online //USB电源连接状态
/sys/class/power_supply/battery/status //充电状态
/sys/class/power_supply/battery/health //电池状态
/sys/class/power_supply/battery/present //使用状态
/sys/class/power_supply/battery/capacity //电池 level
/sys/class/power_supply/battery/batt_vol //电池电压
/sys/class/power_supply/battery/batt_temp //电池温度
/sys/class/power_supply/battery/technology //电池技术

代码框架:


battery_common.c

在Battery驱动模块中,battery_probe函数中会创建一些设备节点,并且运行一个线程bat_thread_kthread获取电池相关的数据信息


battery_kthread_hrtimer_init();//检测电池插入/拔出

kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread");


在bat_thread_kthread线程中

[objc]  view plain   copy
  1. int bat_thread_kthread(voidvoid *x)  
  2. {  
  3.     ktime_t ktime = ktime_set(30);    /* 10s, 10* 1000 ms */  
  4.   
  5. #ifdef BATTERY_CDP_WORKAROUND  
  6.     if (is_usb_rdy() == KAL_FALSE) {  
  7.         battery_log(BAT_LOG_CRTI, "CDP, block\n");  
  8.         wait_event(bat_thread_wq, (is_usb_rdy() == KAL_TRUE));  
  9.         battery_log(BAT_LOG_CRTI, "CDP, free\n");  
  10.     } else{  
  11.         battery_log(BAT_LOG_CRTI, "CDP, PASS\n");  
  12.     }  
  13. #endif  
  14.   
  15.     /* Run on a process content */  
  16.     while (1) {  
  17.         mutex_lock(&bat_mutex);  
  18.   
  19.         if (((chargin_hw_init_done == KAL_TRUE) && (battery_suspended == KAL_FALSE)) || ((chargin_hw_init_done == KAL_TRUE) && (fg_wake_up_bat == KAL_TRUE)))  
  20.             BAT_thread();  
  21.   
  22.         mutex_unlock(&bat_mutex);  
  23.   
  24. #ifdef FG_BAT_INT  
  25.         if(fg_wake_up_bat==KAL_TRUE)  
  26.         {  
  27.             wake_unlock(&battery_fg_lock);  
  28.             fg_wake_up_bat=KAL_FALSE;  
  29.             battery_log(BAT_LOG_CRTI, "unlock battery_fg_lock \n");  
  30.         }  
  31. #endif //#ifdef FG_BAT_INT  
  32.   
  33.         battery_log(BAT_LOG_FULL, "wait event\n");  
  34.   
  35.         wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));  
  36.   
  37.         bat_thread_timeout = KAL_FALSE;  
  38.         hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);  
  39.         ktime = ktime_set(BAT_TASK_PERIOD, 0);  /* 10s, 10* 1000 ms 设置时间为10秒*/  
  40.         if (chr_wake_up_bat == KAL_TRUE && g_smartbook_update != 1/* for charger plug in/ out */  
  41.         {  
  42.             #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)  
  43.             if (DISO_data.chr_get_diso_state) {  
  44.                 DISO_data.chr_get_diso_state = KAL_FALSE;  
  45.                 battery_charging_control(CHARGING_CMD_GET_DISO_STATE, &DISO_data);  
  46.             }  
  47.             #endif  
  48.   
  49.             g_smartbook_update = 0;  
  50.             #if defined(CUST_CAPACITY_OCV2CV_TRANSFORM)  
  51.             battery_meter_set_reset_soc(KAL_FALSE);  
  52.             #endif  
  53.             battery_meter_reset();  
  54.             chr_wake_up_bat = KAL_FALSE;  
  55.   
  56.             battery_log(BAT_LOG_CRTI,  
  57.                         "[BATTERY] Charger plug in/out, Call battery_meter_reset. (%d)\n",  
  58.                         BMT_status.UI_SOC);  
  59.         }  
  60.   
  61.     }  
  62.   
  63.     return 0;  
在这个线程中,每隔10s会去调用函数BAT_Thread去获取电池数据

BAT_Thread

[objc]  view plain   copy
  1. void BAT_thread(void)  
  2. {  
  3.     static kal_bool battery_meter_initilized = KAL_FALSE;  
  4.     if (battery_meter_initilized == KAL_FALSE) {  
  5.         battery_meter_initial();    /* move from battery_probe() to decrease booting time 第一次进该函数会进行一些初始化,如设置D0的值(初始电量,构建电池曲线等) table_init, oam_init*/  
  6.         BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();  
  7.         battery_meter_initilized = KAL_TRUE;  
  8.     }  
  9.   
  10.     mt_battery_charger_detect_check();//充电器型号,是否插入等方面的检测,  
  11.     mt_battery_GetBatteryData();//核心函数获取电池数据  
  12.     if (BMT_status.charger_exist == KAL_TRUE) {  
  13.         check_battery_exist();  
  14.     }  
  15.     mt_battery_thermal_check();//电池温度检测以及开机mode  
  16.     mt_battery_notify_check();//检测电池电压,电流等  
  17.   
  18.     if (BMT_status.charger_exist == KAL_TRUE) {  
  19.         mt_battery_CheckBatteryStatus();//充电异常检测  
  20.         mt_battery_charging_algorithm();//切换充电模式 Pre_CC->CC->CV->Full  
  21.     }  
  22.   
  23.     mt_battery_update_status();//上报电池数据  
  24.     mt_kpoc_power_off_check();  
  25. }  


mt_battery_GetBatteryData:

[objc]  view plain   copy
  1. void mt_battery_GetBatteryData(void)  
  2. {  
  3.     kal_uint32 bat_vol, charger_vol, Vsense, ZCV;  
  4.     kal_int32 ICharging, temperature, temperatureR, temperatureV, SOC;  
  5.     static kal_int32 bat_sum, icharging_sum, temperature_sum;  
  6.     static kal_int32 batteryVoltageBuffer[BATTERY_AVERAGE_SIZE];  
  7.     static kal_int32 batteryCurrentBuffer[BATTERY_AVERAGE_SIZE];  
  8.     static kal_int32 batteryTempBuffer[BATTERY_AVERAGE_SIZE];  
  9.     static kal_uint8 batteryIndex = 0;  
  10.     static kal_int32 previous_SOC = -1;  
  11.   
  12.     bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);  
  13.     Vsense = battery_meter_get_VSense();  
  14.     if( upmu_is_chr_det() == KAL_TRUE ) {  
  15.     ICharging = battery_meter_get_charging_current();  
  16.     } else {  
  17.         ICharging = 0;  
  18.     }  
  19.   
  20.     charger_vol = battery_meter_get_charger_voltage();  
  21.     temperature = battery_meter_get_battery_temperature();  
  22.     temperatureV = battery_meter_get_tempV();  
  23.     temperatureR = battery_meter_get_tempR(temperatureV);  
  24.   
  25.     if (bat_meter_timeout == KAL_TRUE || bat_spm_timeout == TRUE || fg_wake_up_bat== KAL_TRUE)   
  26.     {  
  27.         SOC = battery_meter_get_battery_percentage();//获取电池电量  
  28.         //if (bat_spm_timeout == true)  
  29.             //BMT_status.UI_SOC = battery_meter_get_battery_percentage();  
  30.   
  31.         bat_meter_timeout = KAL_FALSE;  
  32.         bat_spm_timeout = FALSE;  
  33.     } else {  
  34.         if (previous_SOC == -1)  
  35.             SOC = battery_meter_get_battery_percentage();  
  36.         else  
  37.             SOC = previous_SOC;  
  38.     }  
  39.   
  40.     ZCV = battery_meter_get_battery_zcv();  
  41.   
  42.     BMT_status.ICharging =  
  43.         mt_battery_average_method(BATTERY_AVG_CURRENT, &batteryCurrentBuffer[0], ICharging, &icharging_sum,  
  44.                       batteryIndex);  
  45.   
  46.       
  47.     if (previous_SOC == -1 && bat_vol <= batt_cust_data.v_0percent_tracking) {  
  48.         battery_log(BAT_LOG_CRTI,  
  49.                     "battery voltage too low, use ZCV to init average data.\n");  
  50.         BMT_status.bat_vol =  
  51.             mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], ZCV, &bat_sum,  
  52.                           batteryIndex);  
  53.     } else {  
  54.         BMT_status.bat_vol =  
  55.             mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], bat_vol, &bat_sum,  
  56.                           batteryIndex);  
  57.     }  
  58.   
  59.   
  60.     if (battery_cmd_thermal_test_mode == 1)  
  61.     {  
  62.         battery_log(BAT_LOG_CRTI,  
  63.                     "test mode , battery temperature is fixed.\n");   
  64.     }  
  65.     else  
  66.     {  
  67.     BMT_status.temperature =  
  68.         mt_battery_average_method(BATTERY_AVG_TEMP, &batteryTempBuffer[0], temperature, &temperature_sum,  
  69.                       batteryIndex);  
  70.     }  
  71.   
  72.   
  73.     BMT_status.Vsense = Vsense;  
  74.     BMT_status.charger_vol = charger_vol;  
  75.     BMT_status.temperatureV = temperatureV;  
  76.     BMT_status.temperatureR = temperatureR;  
  77.     BMT_status.SOC = SOC;  
  78.     BMT_status.ZCV = ZCV;  
  79.   
  80. #if !defined(CUST_CAPACITY_OCV2CV_TRANSFORM)  
  81.     if (BMT_status.charger_exist == KAL_FALSE) {  
  82.         if (BMT_status.SOC > previous_SOC && previous_SOC >= 0)  
  83.             BMT_status.SOC = previous_SOC;  
  84.     }  
  85. #endif  
  86.   
  87.     previous_SOC = BMT_status.SOC;  
  88.   
  89.     batteryIndex++;  
  90.     if (batteryIndex >= BATTERY_AVERAGE_SIZE)  
  91.         batteryIndex = 0;  
  92.   
  93.   
  94.     if (g_battery_soc_ready == KAL_FALSE)  
  95.         g_battery_soc_ready = KAL_TRUE;  
  96.   
  97.     battery_log(BAT_LOG_CRTI,  
  98.                 "AvgVbat=(%d),bat_vol=(%d),AvgI=(%d),I=(%d),VChr=(%d),AvgT=(%d),T=(%d),pre_SOC=(%d),SOC=(%d),ZCV=(%d)\n",  
  99.                 BMT_status.bat_vol, bat_vol, BMT_status.ICharging, ICharging,  
  100.                 BMT_status.charger_vol, BMT_status.temperature, temperature,  
  101.                 previous_SOC, BMT_status.SOC, BMT_status.ZCV);  
  102.   
  103.   
  104. }  
battery_meter_get_battery_percentage:

[objc]  view plain   copy
  1. kal_int32 battery_meter_get_battery_percentage(void)  
  2. {  
  3. //去掉了一些无效代码  
  4.     if (bat_is_charger_exist() == KAL_FALSE)  
  5.         fg_qmax_update_for_aging_flag = 1;  
  6.   
  7.   
  8.     oam_run();//核心函数  
  9.   
  10.     return (100 - oam_d_5);  
  11.   
  12. }  
oam_run:

[objc]  view plain   copy
  1. void oam_run(void)  
  2. {  
  3.     int vol_bat = 0;  
  4.     /* int vol_bat_hw_ocv=0; */  
  5.     /* int d_hw_ocv=0; */  
  6.     int charging_current = 0;  
  7.     int ret = 0;  
  8.     /* kal_uint32 now_time; */  
  9.     struct timespec now_time;  
  10.     kal_int32 delta_time = 0;  
  11.   
  12.     /* now_time = rtc_read_hw_time(); */  
  13.     get_monotonic_boottime(&now_time);    
  14.   
  15.     /* delta_time = now_time - last_oam_run_time; */  
  16.     delta_time = now_time.tv_sec - last_oam_run_time.tv_sec;  
  17.   
  18.   
  19.     last_oam_run_time = now_time;  
  20.   
  21.     /* Reconstruct table if temp changed; */  
  22.     fgauge_construct_table_by_temp();  
  23.   
  24.   
  25.     vol_bat = 15;       /* set avg times */  
  26.     ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vol_bat);//首先获取电池Vbat端的电压  
  27.   
  28.     oam_i_1 = (((oam_v_ocv_1 - vol_bat) * 1000) * 10) / oam_r_1;    /* 0.1mA  计算电流oam_v_ocv_1为上一次测得的开路电压*/  
  29.     oam_i_2 = (((oam_v_ocv_2 - vol_bat) * 1000) * 10) / oam_r_2;    /* 0.1mA */  
  30.   
  31.     oam_car_1 = (oam_i_1 * delta_time / 3600) + oam_car_1;  /* 0.1mAh 损失/获取 的电量 = i*t 即为放电深度,oam_car_1>0则为放电,反之则为充电*/  
  32.     oam_car_2 = (oam_i_2 * delta_time / 3600) + oam_car_2;  /* 0.1mAh */  
  33.   
  34.     oam_d_1 = oam_d0 + (oam_car_1 * 100 / 10) / gFG_BATT_CAPACITY_aging;//<span style="font-family: Arial, Helvetica, sans-serif;">gFG_BATT_CAPACITY_aging为电池总的容量,在oam_init的时候赋值</span>  
  35.   
  36.     if (oam_d_1 < 0)  
  37.         oam_d_1 = 0;  
  38.     if (oam_d_1 > 100)  
  39.         oam_d_1 = 100;  
  40.   
  41.     oam_d_2 = oam_d0 + (oam_car_2 * 100 / 10) / gFG_BATT_CAPACITY_aging;  
  42.     if (oam_d_2 < 0)  
  43.         oam_d_2 = 0;  
  44.     if (oam_d_2 > 100)  
  45.         oam_d_2 = 100;  
  46.   
  47.     oam_v_ocv_1 = vol_bat + mtk_imp_tracking(vol_bat, oam_i_25);  
  48.   
  49.     oam_d_3 = fgauge_read_d_by_v(oam_v_ocv_1);//算出的开路电压查表获得放电深度  
  50.     if (oam_d_3 < 0)  
  51.         oam_d_3 = 0;  
  52.     if (oam_d_3 > 100)  
  53.         oam_d_3 = 100;  
  54.   
  55.     oam_r_1 = fgauge_read_r_bat_by_v(oam_v_ocv_1);  
  56.   
  57.     oam_v_ocv_2 = fgauge_read_v_by_d(oam_d_2);  
  58.     oam_r_2 = fgauge_read_r_bat_by_v(oam_v_ocv_2);  
  59.   
  60.   
  61.     oam_d_4 = oam_d_3;  
  62.   
  63.     gFG_columb = oam_car_2 / 10;    /* mAh */  
  64.   
  65.     if ((oam_i_1 < 0) || (oam_i_2 < 0))  
  66.         gFG_Is_Charging = KAL_TRUE;  
  67.     else  
  68.         gFG_Is_Charging = KAL_FALSE;  
  69.   
  70.   
  71.     d5_count_time = 60;  
  72.   
  73.     d5_count = d5_count + delta_time;  
  74.     if (d5_count >= d5_count_time) {  
  75.         if (gFG_Is_Charging == KAL_FALSE) {  
  76.             if (oam_d_3 > oam_d_5) { //在放电状态下,oam_d_3大于上一次电量oam_d_5,则电池电量-1  
  77.                 oam_d_5 = oam_d_5 + 1;  
  78.             } else {  
  79.                 if (oam_d_4 > oam_d_5) {  
  80.                     oam_d_5 = oam_d_5 + 1;  
  81.                 }  
  82.             }  
  83.         } else {  
  84.             if (oam_d_5 > oam_d_3) { //<span style="font-family: Arial, Helvetica, sans-serif;">在充电状态下,oam_d_3小于上一次电量oam_d_5,则电池电量+1</span>  
  85.   
  86.                 oam_d_5 = oam_d_5 - 1;  
  87.             } else {  
  88.                 if (oam_d_4 < oam_d_5) {  
  89.                     oam_d_5 = oam_d_5 - 1;  
  90.                 }  
  91.             }  
  92.         }  
  93.         d5_count = 0;  
  94.         oam_d_3_pre = oam_d_3;  
  95.         oam_d_4_pre = oam_d_4;  
  96.     }  
  97.   
  98. }  


oam_run的整个的一个流程如下图所示:



MTK采用的Fuel方案获取剩余电池电量

首先通过adc读取电池 Vbat脚的电压值,然后通过这个闭路电压值查找 R—Table (cust_battery_meter_table.h )获得当前电压和温度下的电池内阻值,然后通过递归回溯的方法得到开路电压 OCV,然后通过这个OCV电压值查找 放电深度表获取当前的放电深度,从而算出剩余的电池电量。


调试驱动时应注意的一些关键点

1、电池曲线

2、充电电流的一些设置(AC_CHARGER_CURRENT,NON_STD_AC_CHARGER_CURRENT,USB_CHARGER_CURRENT等),是否是高压电池HIGH_BATTERY_VOLTAGE_SUPPORT

最高温度: MAX_CHARGE_TEMPERATURE
最高电压: V_CHARGER_MAX

截止满充电流大小:CHARGING_FULL_CURRENT

充关机最大电池差异:CUST_POWERON_DELTA_CAPACITY_TOLRANCE(若小于这个值,则下一次开机用RTC里面存储的剩余电池电量值)

关机电压:SYSTEM_OFF_VOLTAGE

UI电量同步时间:SYNC_TO_REAL_TRACKING_TIME


电池充电驱动流程分析(battery_common.c):

/* Integrate with NVRAM */
ret = alloc_chrdev_region(&adc_cali_devno, 0, 1, ADC_CALI_DEVNAME);

//字符设备的注册,

register_chrdev_region(dev_t first,unsigned int count,char *name)
First :要分配的设备编号范围的初始值(次设备号常设为0); 
Count:连续编号范围. 
Name:编号相关联的设备名称. (/proc/devices); 
动态分配: 
Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
Firstminor : 通常为0; 
*dev:存放返回的设备号; 

Count:连续编号范围. 
Name:编号相关联的设备名称. (/proc/devices); 

adc_cali_cdev = cdev_alloc();

动态申请一个字符设备的内存

adc_cali_cdev->owner = THIS_MODULE;
adc_cali_cdev->ops = &adc_cali_fops;
ret = cdev_add(adc_cali_cdev, adc_cali_devno, 1)//adc_cali_devno:设备号,前20位是主设备好,后12位此设备号  adc_cali_cdev:设备的结构体

        adc_cali_major = MAJOR(adc_cali_devno);  //获取主设备号
adc_cali_class = class_create(THIS_MODULE, ADC_CALI_DEVNAME);, 1);

class_dev = (struct class_device *)device_create(adc_cali_class,
NULL,
adc_cali_devno, NULL, ADC_CALI_DEVNAME);

get_charging_control();

battery_charging_control = chr_control_interface;

status = charging_func[cmd](data);

static kal_uint32 (* const charging_func[CHARGING_CMD_NUMBER])(void *data)=
 {
   
      charging_hw_init
,charging_dump_register
,charging_enable
,charging_set_cv_voltage
,charging_get_current
,charging_set_current
  

......

}

/* Integrate with Android Battery Service */
ret = power_supply_register(&(dev->dev), &ac_main.psy);

BMT_status.bat_charging_state = CHR_PRE;
BMT_status.bat_in_recharging_state = KAL_FALSE;
BMT_status.bat_full = KAL_FALSE;
BMT_status.nPercent_ZCV = 0; 初始化状态


battery_kthread_hrtimer_init(); 定时器初始化

kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); 创建并让线程一直运行起来


/*LOG System Set */
init_proc_log();


bat_thread_kthread:

{

wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));

}

 void BAT_thread(void)
{
static kal_bool battery_meter_initilized = KAL_FALSE;
if (battery_meter_initilized == KAL_FALSE) {
battery_meter_initial();/* move from battery_probe() to decrease booting time */
BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
battery_meter_initilized = KAL_TRUE;
}


mt_battery_charger_detect_check();
mt_battery_GetBatteryData();
if (BMT_status.charger_exist == KAL_TRUE) {
check_battery_exist();
}
mt_battery_thermal_check();
mt_battery_notify_check();


if (BMT_status.charger_exist == KAL_TRUE) {
mt_battery_CheckBatteryStatus();  //检查充电状态,选择CC_PRE开始,或其他非正常状态,
mt_battery_charging_algorithm();  //真正的充电开始,如果一直在CC_PRE状态,则会反复判断是否达到

进入CC状态的条件,以此类推,状态这样切换
}


mt_battery_update_status();
mt_kpoc_power_off_check();
}


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/stoic163/article/details/72580355

智能推荐

java构造方法,对象的创建过程,数据类型的引用_清如许.的博客-程序员宝宝

构造方法:构造方法没有 返回值类型方法名必须和类名相同(一个类中要想用多个构造方法只能用重载) 构造方法不允许手工调用,在对象构造过程中自动调用1次;(好比人类中的剪脐带,只在出生的时候剪一次)作用:给实例中的对象赋值;在现实生活中,很多事物一出现,就天生具有某些属性和行为。比如人一出生,就有年龄、身高、体重、就会哭;汽车一出产,就有颜色、有外观、可以运行等。这些,...

tapestry参数_dnnlyqai的博客-程序员宝宝

tapestry如何携带两个参数啊,晕比如是一个参数的,如果还想在添加一个参数该怎样处理啊? 

Executor, ExecutorService 和 Executors 间的不同_麦晓宇的博客-程序员宝宝

java.util.concurrent.Executor, java.util.concurrent.ExecutorService, java.util.concurrent. Executors 这三者均是 Java Executor 框架的一部分,用来提供线程池的功能。因为创建和管理线程非常心累,并且操作系统通常对线程数有限制,所以建议使用线程池来并发执行任务,而不是每次请求进来时创建

java实现验证码登录_C18298182575的博客-程序员宝宝_java登录验证码实现

一,场景:用户登录时需要输入验证码登录,如何实现用户通过验证码登录二,实现逻辑1,进入登录页面时,调用生成验证码接口,入参:当前时间戳(前端传入)2,后台调用生成验证码接口,生成验证码,并以入参时间戳为 key,验证码为value,保存在redis,并设置有效时间为1分钟,超时需要重新输入3,用户输入验证码,调用后台登录接口,入参:用户名,密码,验证码,key4,登录时校验,比...

小白学开发(iOS)OC_定义一个类(2015-07-21)_「已注销」的博客-程序员宝宝

////  main.m//  定义一个类////  Created by admin on 15/7/22.//  Copyright (c) 2015年 admin. All rights reserved.//#import /*    1. 定义一个类有三部分:        类名            要求:> 类名的首字母 必须 大写

随便推点

c#FindWindow及mouse_event_Melina0_0的博客-程序员宝宝

有时候需要用代码控制外部APP的一些操作,比如点击注册或者其他,这就需要用findwinow去抓取界面的句柄等,或者用mouse_event直接点击屏幕的某些位置。首先,引用命名空间及调用dllusing System.Runtime.InteropServices;[DllImport("user32.dll")]static extern IntPtr FindWindow(string lpClassName, string lpWindowName);[DllImport("user32.

关于serveletContext.getRealPath()方法_songchunyi的博客-程序员宝宝_getrealpath

关于serveletContext.getRealPath()方法from http://www.java3z.com/cwbwebhome/article/article2/210218.html1.关于request.getRealPath问题:String filename=request.getRealPath(filename)------------------

svn清除,查看当前登录的用户名密码_C P X的博客-程序员宝宝_查看svn自己用户密码

一般用户登录svn并记住用户密码后,下次再登录的时候将不需要输入用户密码,导致电脑使用着登录的时候,不知道到底登录的是个用户,只能将数据清除1.项目文件夹清除:直接查看项目当中的隐藏文件夹,找到.svn这个文件删除即可2.编译器中(这里以idea为例):重启Idea,然后点击SVN就可以看到需要重新输入帐号密码了想查看svn的账号密码:svn登录用户的文件,存放位置:C:\Users...

shiro过滤器失效问题研究_timy07的博客-程序员宝宝

问题背景项目使用了shiro 过滤器拦截请求,做一些限流,鉴权,白名单限制的事情,可是最近在上线一个新功能时,新增了一个拦截路径,上线后,发现部分设置了拦截的路径失效,导致项目回滚问题定位之前在本地开发环境出现过类似问题,怀疑是正则表达式覆盖或者是拦截器排序规则导致,可是查了一堆网上资料,均没有类似情况,加之是本地环境问题,也就草草了之了。今天在线上环境碰到就不得不去查明原因,彻底解决。这...

ORA-01102: cannot mount database in EXCLUSIVE mode_飞狐在天的博客-程序员宝宝

今天在STARTUP一数据库时,发生如下错误:SQL> conn /as sysdbaConnected to an idle instance.SQL> startuporacle instance started.Total System Global Area 276824064 bytesFixed Size 778736 bytesVariable Size

SSH和SSM的区别_墨羅的博客-程序员宝宝

SSH和SSM的区别加粗样式SSH是Spring+Struts2+Hibernate是目前较流行的一种Web应用程序开源集成框架。SSM是Spring+SpringMVC+MyBatis常作为数据源较简单的web项目的框架。Spring的核心功能加粗样式控制反转(IOC) &amp; 依赖注入(DI)控制反转(IOC)SpringMVC的概念加粗样式SpringMVC是Spring生态圈中的WEB-MVC框架Hibernate加粗样式是一个开放源代码的对象关系映射框架,程序员可以更加轻松的操

推荐文章

热门文章

相关标签