当前位置: 首页 > news >正文

【C5】111

文章目录

  • bmc_wtd:syscpld.c中wd_en和wd_kick节点对应寄存器,crontab,FUNCNAME
  • AST2500/2600 WDT切换主备:BMC用WDT2作为主备切换的watchdog控制器
    • AC后读取:bmc处于主primary flash(设完后:实际主,wtd1主,wtd2主)
    • 切换spi备:wtd2的2c寄存器设为0x93,换另一个flash后reboot后从备起(设完后:实际备,wtd1主,wtd2备)
    • 用WDT1切主:(设完后:实际备,wtd1备,wtd2备)
    • 用WDT2切主:(设完后:实际备,wtd1备,wtd2主)
    • 用WDT1切主:(设完后:实际主,wtd1主,wtd2主)
    • 关于清空寄存器:(设完后:WTD1主,WTD2主,实际主)
    • 结论:从主切到备,需要一个wdt的status是default也就是0的wdt,然后用0x93切换
  • BMC喂狗实现:sys/class/gpio/gpio1/value获取gpio1值
      • watch-dog.h
      • watch-dog.c
      • main.c
      • Makefile
      • run-watch-dog.sh
      • setup-watch-dog.sh
      • watch-dog_0.1.bb
  • post code


bmc_wtd:syscpld.c中wd_en和wd_kick节点对应寄存器,crontab,FUNCNAME

在这里插入图片描述

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/binWATCHDOG_LOG="/tmp/watchdog.log"usage(){program=$(basename "$0")echo "Usage:"echo "$program <operation>"echo "  <operation>  : start stop kick query restart"echo "Examples:"echo "  $program start"echo ""
}kick()
{ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenecho "0x7c" > /sys/bus/i2c/devices/0-000d/wd_kickelseusageexitfiret=$(date)echo "$ret ${FUNCNAME[0]}" >> $WATCHDOG_LOG
}enable()
{ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" != "0x1" ];thenecho "0x1" > /sys/bus/i2c/devices/0-000d/wd_enelseusageexitfiret=$(date)echo "$ret ${FUNCNAME[0]}" > $WATCHDOG_LOG
}disable()
{ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenecho "0x0" > /sys/bus/i2c/devices/0-000d/wd_enecho "0x7c" > /sys/bus/i2c/devices/0-000d/wd_kickelseusageexitfiret=$(date)echo "$ret ${FUNCNAME[0]}" >> $WATCHDOG_LOG
}check_parameter()
{if [ $# -ne 1 ];thenusageexitficase ${1} in"start" | "stop" | "kick" |"query" |"restart");;*)      #除上面的其他的usageexit;;esac
}check_parameter "$@"case ${1} in"start")ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenusageexitfienablekick;;"stop")disableexit;;"kick")kickexit;;"restart")ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenusageexitfienablekickexit;;"query")ret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenecho "ENABLE"elseecho "DISABLE"fiexit;;
esacwhile true
doret=$(head -1  /sys/bus/i2c/devices/0-000d/wd_en)if [ "$ret" = "0x1" ];thenkickfisleep 30
done
root@bmc-oob:~# ps | grep wd588 root      2904 S    runsv /etc/sv/wd591 root      3036 S    {wd} /bin/bash /usr/local/bin/wd start779 root      3036 S    grep wd
root@bmc-oob:~# wd query
ENABLE
root@bmc-oob:~# wd stop
root@bmc-oob:~# wd query
DISABLE
root@bmc-oob:~# wd restart
root@bmc-oob:~# wd kick
root@bmc-oob:~# wd query
ENABLE
init()
{ret=$(ps |grep crond|grep -v grep)if [ "x$ret" = "x" ];thenecho "No found crond process"exitfiif [ ! -d /crontabs ];thenmkdir /crontabstouch /crontabs/rootficrontab -c /etc/cron/crontabs/ /etc/cron/crontabs/rootcp /var/log/watchdog.sh /usr/local/bin/watchdog.sh
}add_task()
{echo "* * * * * /usr/local/bin/watchdog.sh kick" >> /etc/cron/crontabs/rootecho "* * * * * date >> /var/log/date.log" >> /etc/cron/crontabs/root
}del_task()
{sed -i "/\* \* \* \* \* \/usr\/local\/bin\/watchdog.sh kick/d" /etc/cron/crontabs/root
}

AST2500/2600 WDT切换主备:BMC用WDT2作为主备切换的watchdog控制器

AC后读取:bmc处于主primary flash(设完后:实际主,wtd1主,wtd2主)

在这里插入图片描述
如下0x100代表default flash。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

切换spi备:wtd2的2c寄存器设为0x93,换另一个flash后reboot后从备起(设完后:实际备,wtd1主,wtd2备)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下202第1位(不是第0位)和第9位置为1,发现这时确实WDT2可控,当前在备flash启动。
在这里插入图片描述

用WDT1切主:(设完后:实际备,wtd1备,wtd2备)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

用WDT2切主:(设完后:实际备,wtd1备,wtd2主)

在这里插入图片描述
在这里插入图片描述

用WDT1切主:(设完后:实际主,wtd1主,wtd2主)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

关于清空寄存器:(设完后:WTD1主,WTD2主,实际主)

在这里插入图片描述
在这里插入图片描述
wdt1和wdt2都切到备flash。
在这里插入图片描述
如下clear寄存器清除wdt1的status,保留了reset次数,但是将code source(主备)清除为0(主)。
在这里插入图片描述
再用wdt2切换主。
在这里插入图片描述
这次切到了主。
在这里插入图片描述
用wdt1切换到备。
在这里插入图片描述
清空wdt1的status。这时如果用我们的测试脚本bootsource会判断是在主,其实是在备。
在这里插入图片描述
尝试wdt1用0x13切换主,成功切到主。
在这里插入图片描述
在这里插入图片描述

结论:从主切到备,需要一个wdt的status是default也就是0的wdt,然后用0x93切换

从备切到主,需要满足两(三)个wdt中都从备切到主。比如wdt1是备,wdt2是备,那要对wdt1,wdt2都下一次0x93。如果wdt1,wdt2中一个是备,那对对应的wdt下0x93。

还有因为清空寄存器造成的虽然在备,但是wdt都是显示在主,这时候用0x13就可以切到主。用wdt2进行切换主备。避免使用清空寄存器0x14/0x34。

a=0x00000100 #256
b=$(( ((a & 0xff00) >> 8 ) ))
c=$((a & 0xff00))
d=$((a >> 8))
echo $b
echo $c
echo $d
# yutao@obmc-server:~/bak$ ./a.sh 
# 1
# 256
# 1# 检查当前BMC是在主还是备启动的检查函数boot_source实现如下:
check_boot_source()
{# Please refer to reg WDT1/WDT2 Control Register definition to# understand this code block, WDT1 is on page 646 of ast2500v16.pdf# and WDT2 is on page 649 of ast2500v16.pdf# get watch dog1 timeout status registerwdt1=$(devmem 0x1e785010)# get watch dog2 timeout status registerwdt2=$(devmem 0x1e785030)wdt1_timeout_cnt=$(( ((wdt1 & 0xff00) >> 8) ))  #取出高8位,自动转为十进制wdt2_timeout_cnt=$(( ((wdt2 & 0xff00) >> 8) ))wdt1_boot_code_source=$(( ((wdt1 & 0x2) >> 1) )) #取出第1位(不是第0)wdt2_boot_code_source=$(( ((wdt2 & 0x2) >> 1) ))boot_code_source=0# Check both WDT1 and WDT2 to indicate the boot sourceif [ $wdt1_timeout_cnt -ge 1 ] && [ $wdt1_boot_code_source -eq 1 ]; thenboot_code_source=1elif [ $wdt2_timeout_cnt -ge 1 ] && [ $wdt2_boot_code_source -eq 1 ]; thenboot_code_source=1fiecho $boot_code_source
}bmc_boot_info() {wdt1=$(devmem 0x1e785010)wdt2=$(devmem 0x1e785030)wdt1_timeout_cnt=$(( ((wdt1 & 0xff00) >> 8) ))wdt2_timeout_cnt=$(( ((wdt2 & 0xff00) >> 8) ))boot_code_source=$(check_boot_source)boot_source="Master Flash"if [ $((boot_code_source)) -eq 1 ]; thenboot_source="Slave Flash"fiecho "WDT1 Timeout Count: " $wdt1_timeout_cntecho "WDT2 Timeout Count: " $wdt2_timeout_cntecho "Current BMC Boot Code Source: $boot_source"
}bmc_boot_from() {# Enable watchdog reset_system_after_timeout bit and WDT_enable_signal bit.# Refer to ast2500v16.pdf page 650th.boot_source=0x00000013boot_code_source=$(check_boot_source)if [ "$1" = "master" ]; thenif [ $((boot_code_source)) -eq 0 ]; thenecho "Current boot source is master, no need to switch."return 0fi# Set bit_7 to 0 : Use default boot code whenever WDT reset.boot_source=0x00000033elif [ "$1" = "slave" ]; thenif [ $((boot_code_source)) -eq 1 ]; thenecho "Current boot source is slave, no need to switch."return 0fi# No matter BMC boot from any one of master and slave.# Set bit_7 to 1 : Use second boot code whenever WDT reset.# And the sencond boot code stands for the other boot source.boot_source=0x000000b3fiecho "BMC will switch to $1 after 10 seconds..."/usr/local/bin/watch-dog stop# Clear WDT1 counter and boot code source statusdevmem 0x1e785014 w 0x77# Clear WDT2 counter and boot code source statusdevmem 0x1e785034 w 0x77# Set WDT time out 10s, 0x00989680 = 10,000,000 usdevmem 0x1e785024 32 0x00989680# WDT magic number to restart WDT counter to decrease.devmem 0x1e785028 32 0x4755devmem 0x1e78502c 32 $boot_source
}

BMC喂狗实现:sys/class/gpio/gpio1/value获取gpio1值

bmc喂狗gpio硬件管脚:
在这里插入图片描述
在这里插入图片描述
bmc监听gpio中断硬件管脚:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

导出GPIO:echo $gpio_num > /sys/class/gpio/exporteg: echo 1 > /sys/class/gpio/export执行完以上命令后,如果该gpio接口存在且未被占用则会出现如下目录:/sys/class/gpio/gpio1设置方向:gpio的方向分为两类:in和outin:表示该gpio用于输入。(如该gpio连接一个按钮)out:表示该gpio用于输出。(如该gpio连接一个led灯)指定为in模式的命令:echo in > /sys/class/gpio/gpio1/direction指定为out模式的命令如下:echo out > /sys/class/gpio/gpio1/direction //默认value为0echo low > /sys/class/gpio/gpio1/direction //指定方向为out且value为0echo high > /sys/class/gpio/gpio1/direction //指定方向为out且value为1设置高低:只用当方向为out模式时才能指定gpio接口的电压的高低。这个很容易理解,因为如果是in模式的话,它的电平高低取决于所连接外设的电平高低,我们只能读取它的值,不能更改它的值echo 1 > /sys/class/gpio/gpio1/value //指定gpio1为高电平echo 0 > /sys/class/gpio/gpio1/value //指定gpio1为低电平    

在这里插入图片描述
在这里插入图片描述

watch-dog.h

在这里插入图片描述

#ifndef SENSOR_MON__h
#define SENSOR_MON__h#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h> 
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <dirent.h>
#include <stdarg.h>
#include <syslog.h>
#include <openbmc/libgpio.h>
#include <fcntl.h>
#include <stdbool.h>
#include <poll.h>
#include <ctype.h>
#include <assert.h>
#include <libgen.h>
#include <linux/limits.h>//#define GPIO_KICK_NUM    885
//#define GPIO_KICK_NAME   "GPIOL5"
#define WDT_MASK_PATH "/sys/bus/i2c/devices/82-000d/bmc_wdt_mask"
#define GPIO_KICK_SHADOW "BMC_CPLD_GPIO69_WDO"typedef enum {WD_FUNC_START,  //0WD_FUNC_STOP,WD_FUNC_KICK,WD_FUNC_UNKNOWN,
} wd_func;typedef enum {MASK_ENABLE = 1,MASK_DISABLE = 0,
} wd_mask;// 如下LOG替换syslog , syslog像printf定义在<syslog.h>, 打印在/var/log/message
#define LOG(mode,format, ...)   syslog(mode, format, __VA_ARGS__)int bmc_wd_set(wd_mask value);
void feed_dog_func();#endif

watch-dog.c

#include "watch-dog.h"int bmc_wd_set(wd_mask value){   // bmc设置cpld寄存器控制wtd芯片(是外置芯片,不是bmc芯片内置的)开关FILE* pFile = fopen(WDT_MASK_PATH, "w");char regvalue[4]= {0};int ret = 0;if(value == MASK_DISABLE){ // 0sprintf(regvalue,"0x0");}else if(value == MASK_ENABLE){sprintf(regvalue,"0x1");}ret = fwrite(regvalue, sizeof(regvalue) , 1, pFile );  //ret为次数即fwrite中的1if(ret==1){fflush(pFile);ret = 0;}else{ret = -1;}fclose(pFile);return ret;
}void feed_dog_func()   // bmc通过gpio的0.5s高低电平来喂狗
{int ret = 0;struct timespec n_sleep;n_sleep.tv_sec = 0; //secondes, integer part sleep duration    // 整数n_sleep.tv_nsec = 5e8L; //nanoseconds, decimal part sleep duration   // 小数  0.5s(上行整数0,这行小数5)gpio_desc_t* desc = gpio_open_by_shadow(GPIO_KICK_SHADOW);  // libgpio-ctrl.so中的接口if (!desc) {syslog(LOG_INFO ,"gpio_open_by_shadow fail\n");return ;}ret = gpio_set_direction(desc, GPIO_DIRECTION_OUT);if (ret == -1){syslog(LOG_ERR ,"gpio_change_direction err \n");gpio_close(desc);return ;}ret = gpio_set_edge(desc, GPIO_EDGE_NONE);if (ret == -1){syslog(LOG_ERR ,"gpio_change_edge err \n");gpio_close(desc);return ;}
//BMC启动时,喂狗(硬件gpio管脚,每隔500ms翻转一次高低电平),并关闭中断MASK如下:
//cmm cpld 0X71 地址 bit0 是中断MASK (为1时MASK使能即看门狗关闭;为0时MASK失效即看门狗打开)
//i2cset -f -y 82 0xd 0x71 0xfe 做成bmc_wdt_mask节点ret=bmc_wd_set(MASK_DISABLE);  // 0开wtdif(ret == 0){syslog(LOG_INFO ,"bmc_wd_set OK\n");}else{syslog(LOG_ERR ,"bmc_wd_set Fail\n");gpio_close(desc);return;}while(1){gpio_set_value(desc,GPIO_VALUE_HIGH);nanosleep(&n_sleep, NULL);  // 0.5s 高电平gpio_set_value(desc,GPIO_VALUE_LOW);nanosleep(&n_sleep, NULL);   // 0.5s 低电平}gpio_close(desc);return ;
}

main.c

#include "watch-dog.h"int func_start()
{int ret = 0;ret=bmc_wd_set(MASK_DISABLE);  //mask和disable都是否定if(ret == 0){syslog(LOG_INFO ,"func_start OK\n");}else{syslog(LOG_ERR ,"func_start Fail\n");return -1;}return 0;
}int func_stop()
{int ret = 0;ret=bmc_wd_set(MASK_ENABLE);if(ret == 0){syslog(LOG_INFO ,"func_stop OK\n");}else{syslog(LOG_ERR ,"func_stop Fail\n");return -1;}return 0;
}void usage(void)
{fprintf(stderr, "usage: watch-dog <start/stop/kick> \n");exit (1);
}int func_kick()
{int rc,ret,pid_file;int pid_value;char piddata[12];char file_path[60];pthread_t tid_feed;ret = snprintf(file_path, sizeof(file_path), "/var/run/watch_dog.pid");  // /var/run/a 也可以,记录当前进程pid号if ((ret < 0) || (ret >= sizeof(file_path))) {syslog(LOG_ERR ,"watch_dog:too long for lockfile\n");return -1;}pid_file = open(file_path, O_CREAT | O_RDWR, 0666);if (pid_file < 0) {syslog(LOG_ERR ,"watch_dog: failed to acquire lock\n");exit(1);}else{pid_value=getpid();snprintf(piddata, sizeof(piddata), "%d\n", pid_value);ret=write(pid_file, piddata, sizeof(piddata));  //先open再writeif(ret < 0) {syslog(LOG_ERR ,"watch_dog: write pid err\n");}}rc = flock(pid_file, LOCK_EX | LOCK_NB); // Linux文件锁flock: 检测进程是否已经存在if(rc){if(EWOULDBLOCK == errno){syslog(LOG_ERR ,"Another watch_dog instance is running...\n");exit(1);}}syslog(LOG_INFO ,"watch_dog: daemon started\n");pthread_create(&tid_feed,NULL,(void *)feed_dog_func,NULL);  //一个pthread_create只创建一个线程pthread_join(tid_feed,NULL);if (pid_file >= 0) {unlink(file_path);  //#include<unistd.h> , unlink删除文件}syslog(LOG_INFO ,"watch_dog: daemon end\n");return 0;
}wd_func wd_func_judge(char * desc)
{if (!strcmp(desc, "start")){   // strcmp相同返回0,if(1)执行,shell中if(0)执行return WD_FUNC_START;}else if (!strcmp(desc, "stop")){return WD_FUNC_STOP;}else if (!strcmp(desc, "kick")){return WD_FUNC_KICK;}return WD_FUNC_UNKNOWN;
}int main(int argc, char* argv[])
{wd_func wd_func_sel = WD_FUNC_UNKNOWN;if (argc != 2) {usage();}wd_func_sel = wd_func_judge(argv[1]);if ( wd_func_sel == WD_FUNC_UNKNOWN ){usage();}switch (wd_func_sel){case WD_FUNC_START :func_start();break;case WD_FUNC_STOP :func_stop();break;case WD_FUNC_KICK :func_kick();break;default :break;}return 0;
}

Makefile

#
all: watch-dog
SRC = $(wildcard ./*.c)
CFLAGS += -Wall -Werror -D _XOPEN_SOURCE -pthread -lm -std=c99watch-dog: $(SRC)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS).PHONY: cleanclean:rm -rf *.o watch-dog

run-watch-dog.sh

exec /usr/local/bin/watch-dog kick

setup-watch-dog.sh

WDTFUNC=/usr/local/bin/watch-dog
# /etc/init.d/setup-watch-dog.sh: start and stop the watch-dog
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin:/usr/local/bin"
case "$1" instart)echo -n "Starting watch dog kick daemon..."runsv /etc/sv/watch-dog > /dev/null 2>&1 &  # runsv找/etc/sv/watch-dog/run文件运行echo "done.";;stop)echo -n "Stopping watch dog daemon..."$WDTFUNC stop > /dev/null 2>&1 &echo "done.";;*)echo "Usage: /etc/init.d/setup-watch-dog.sh {start|stop}"exit 1;;
esac
exit 0

watch-dog_0.1.bb

SUMMARY = "watch dog Daemon"
DESCRIPTION = "Daemon for watch dog"
SECTION = "base"
PR = "r1"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
SRC_URI = "file://COPYING \file://main.c \file://watch-dog.c \file://watch-dog.h \file://Makefile \file://setup-watch-dog.sh \file://run-watch-dog.sh \"
S = "${WORKDIR}"
binfiles = "watch-dog \"
pkgdir = "watch-dog"
LDFLAGS = "-lgpio-ctrl"
DEPENDS += "libgpio-ctrl update-rc.d-native"
RDEPENDS_${PN} += "libgpio-ctrl bash"install_sysv() {install -d ${D}${sysconfdir}/init.dinstall -d ${D}${sysconfdir}/rcS.dinstall -d ${D}${sysconfdir}/svinstall -d ${D}${sysconfdir}/sv/watch-doginstall -d ${D}${sysconfdir}/watch-doginstall -m 755 setup-watch-dog.sh ${D}${sysconfdir}/init.d/setup-watch-dog.shinstall -m 755 run-watch-dog.sh ${D}${sysconfdir}/sv/watch-dog/run  #将run-watch-dog.sh复制到/etc/sv/watch-dog/run文件里update-rc.d -r ${D} setup-watch-dog.sh defaults 93 5  #defaults :开机自动执行setup-watch-dog.sh start ,reboot自动执行setup-watch-dog.sh stop
}do_install() {dst="${D}/usr/local/fbpackages/${pkgdir}"bin="${D}/usr/local/bin"install -d $dstinstall -d $binfor f in ${binfiles}; doinstall -m 755 $f ${dst}/$fln -snf ../fbpackages/${pkgdir}/$f ${bin}/$fdoneinstall_sysv
}FBPACKAGEDIR = "${prefix}/local/fbpackages"
FILES_${PN} = "${FBPACKAGEDIR}/watch-dog ${prefix}/local/bin ${sysconfdir}"

post code

在这里插入图片描述

// obmc-pal.c
/* IPMI SEL: System Firmware Error string table */
struct system_fw_progress {uint8_t EventData1;char DecodeString[128];
};struct system_fw_progress system_fw_error[] = {{0x00, "Unspecified"},   // 一个{}就是一个system_fw_progress结构体,129字节{0x01, "No system memory is physically installed in the system"},{0x02, "No usable system memory, all installed memory has experienced an unrecoverable failure"}, // 88字节{0x03, "Unrecoverable hard-disk/ATAPI/IDE device failure"},{0x04, "Unrecoverable system-board failure"},{0x05, "Unrecoverable diskette subsystem failure"},{0x06, "Unrecoverable hard-disk controller failure"},{0x07, "Unrecoverable PS/2 or USB keyboard failure"},{0x08, "Removable boot media not found"},{0x09, "Unrecoverable video controller failure"},{0x0A, "No video device detected"},{0x0B, "Firmware (BIOS) ROM corruption detected"},{0x0C, "CPU voltage mismatch"},{0x0D, "CPU speed matching failure"},
};struct system_fw_progress system_fw_hang_or_progress[] = {{0x00, "Unspecified"},{0x01, "Memory initialization"},{0x02, "Hard-disk initialization"},{0x03, "Secondary processor(s) initialization"},{0x04, "User authentication"},{0x05, "User-initiated system setup"},{0x06, "USB resource configuration"},{0x07, "PCI resource configuration"},{0x08, "Option ROM initialization"},{0x09, "Video initialization"},{0x0A, "Cache initialization"},{0x0B, "SM Bus initialization"},{0x0C, "Keyboard controller initialization"},{0x0D, "Embedded controller/management controller initialization"},{0x0E, "Docking station attachment"},{0x0F, "Enabling docking station"},{0x10, "Docking station ejection"},{0x11, "Disabling docking station"},{0x12, "Calling operating system wake-up vector"},{0x13, "Starting operating system boot process, e.g. calling Int 19h"},{0x14, "Baseboard or motherboard initialization"},{0x15, "reserved"},{0x16, "Floppy initialization"},{0x17, "Keyboard test"},{0x18, "Pointing device test"},{0x19, "Primary processor initialization"},
};uint8_t *ed = &event_data[3];char temp_log[512] = {0};char add_sol_log_com[512] = "logger -p local3.info ";case POST_ERROR:if (((ed[0] >> 6) & 0x03) == 0x3) {  // table29 eventdata1第6和7位为11switch (ed[0] & 0xF) { // table29取eventdata1低四位case 0x00: // sensor offsetstrcat(error_log, "System Firmware Error (POST Error), IPMI Post Code"); // 50字节if (ed[1] <  (sizeof(system_fw_error) / sizeof(system_fw_error[0]))) { // 13*129/129=0x0dsprintf(temp_log, ", %s", system_fw_error[ed[1]].DecodeString); // 88字节,ed[1]即eventdata2} else {sprintf(temp_log, ", reserved");}break;case 0x01:strcat(error_log, "System Firmware Hang, IPMI Post Code");case 0x02:if (strcmp(error_log, "") == 0) {strcat(error_log, "System Firmware Progress, IPMI Post Code");}if (ed[1] <  (sizeof(system_fw_hang_or_progress) / sizeof(system_fw_hang_or_progress[0]))) {sprintf(temp_log, ", %s", system_fw_hang_or_progress[ed[1]].DecodeString);} else {sprintf(temp_log, ", reserved");}break;default:sprintf(temp_log, "Unknown");break;}strcat(error_log, temp_log); //138// send post code sel to sol logsprintf(temp_log, " '%s' ", error_log);strcat(add_sol_log_com, temp_log);system(add_sol_log_com);break;

在这里插入图片描述
在这里插入图片描述

相关文章:

【C5】111

文章目录bmc_wtd&#xff1a;syscpld.c中wd_en和wd_kick节点对应寄存器&#xff0c;crontab&#xff0c;FUNCNAMEAST2500/2600 WDT切换主备&#xff1a;BMC用WDT2作为主备切换的watchdog控制器AC后读取&#xff1a;bmc处于主primary flash&#xff08;设完后&#xff1a;实际主…...

静态成员,友元函数

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…...

数学分析课程笔记(张平):函数

01 函数 \quad作为数学分析的第一节课&#xff0c;首先深入了解一下函数。 \quad翻看一些教材可以发现&#xff0c;有些教材将“函数”与“映射”区分为两个概念&#xff0c;有些教材&#xff08;尤其是前苏联时期的一些教材&#xff09;则将其视为一个概念。实际上&#xff0c…...

spring事务 只读此文

文章目录一. 事务概述1.1. MySQL 数据库事务1.2 spring的事务支持:1.2.1 编程式事务&#xff1a;1.2.2 声明式事务1.2.3 事务传播行为&#xff1a;1.2.4 事务隔离级别1.2.5 事务的超时时间1.2.6 事务的只读属性1.2.7 事务的回滚策略二. spring事务&#xff08;注解 Transaction…...

真实的软件测试日常工作是咋样的?

最近很多粉丝问我&#xff0c;小姐姐&#xff0c;现在大环境不景气&#xff0c;传统行业不好做了&#xff0c;想转行软件测试&#xff0c;想知道软件测试日常工作是咋样的&#xff1f;平常的工作内容是什么&#xff1f; 别急&#xff0c;今天跟大家细细说一下一个合格的软件测…...

【UML】软件需求说明书

目录&#x1f981; 故事的开端一. &#x1f981; 引言1.1编写目的1.2背景1.3定义1.4参考资料二. &#x1f981; 任务概述2.1目标2.2用户的特点2.3假定和约束三. &#x1f981; 需求规定3.1 功能性需求3.1.1系统用例图3.1.2用户登录用例3.1.3学员注册用例3.1.4 学员修改个人信息…...

面试官:html里面哪个元素可以让文字换行展示

在HTML中&#xff0c;可以使用 <br> 元素来强制换行&#xff0c;也可以使用CSS的 word-break 或 white-space 属性来实现自动换行。以下是这些方法的具体说明&#xff1a; 1.使用 <br> 元素 <br> 元素可以在文本中插入一个换行符&#xff0c;使文本从该位置…...

XGBoost和LightGBM时间序列预测对比

XGBoost和LightGBM都是目前非常流行的基于决策树的机器学习模型&#xff0c;它们都有着高效的性能表现&#xff0c;但是在某些情况下&#xff0c;它们也有着不同的特点。 XGBoost和LightGBM简单对比 训练速度 LightGBM相较于xgboost在训练速度方面有明显的优势。这是因为Ligh…...

JVM高频面试题

1、项目中什么情况下会内存溢出&#xff0c;怎么解决&#xff1f; &#xff08;1&#xff09;误用固定大小线程池导致内存溢出 Excutors.newFixedThreadPool内最大线程数是21亿(2) 误用带缓冲线程池导致内存溢出最大线程数是21亿(3)一次查询太多的数据&#xff0c;导致内存占用…...

Windows环境下实现设计模式——状态模式(JAVA版)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows环境下如何编程实现状态模式&#xff08;设计模式&#xff09;。不知道大家有没有这样的感觉&#xff0c;看了一大堆编程和设计模式的书&#xff0c;却还是很难理解设计模式&#xff0c;无…...

【总结】多个条件排序(pii/struct/bool)

目录 pii struct bool pii 现在小龙同学要吃掉它们&#xff0c;已知他有n颗苹果&#xff0c;并且打算每天吃一个。 但是古人云&#xff0c;早上金苹果&#xff0c;晚上毒苹果。由此可见&#xff0c;早上吃苹果和晚上吃苹果的效果是不一样的。 已知小龙同学在第 i 天早上吃苹果能…...

基于stm32mp157 linux开发板ARM裸机开发教程Cortex-A7 开发环境搭建(连载中)

前言&#xff1a;目前针对ARM Cortex-A7裸机开发文档及视频进行了二次升级持续更新中&#xff0c;使其内容更加丰富&#xff0c;讲解更加细致&#xff0c;全文所使用的开发平台均为华清远见FS-MP1A开发板&#xff08;STM32MP157开发板&#xff09;针对对FS-MP1A开发板&#xff…...

最适合游戏开发的语言是什么?

建议初学者学习主流的开发技术 主流开发技术有大量成熟的教程、很多可以交流的学习者、及时的学习反馈等&#xff1b;技术的内里基本都是相同的&#xff0c;学习主流技术的经验、知识可以更好更快地疏通学习新知识和技术。 因此&#xff0c;对C#或者C二选一进行学习较好。 Un…...

C语言刷题(7)(字符串旋转问题)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容依旧是复习之前的知识点&#xff0c;那么&#xff0c;就是做一道小小的题目啦&#xff0c;下面&#xff0c;让我们进入C语言的世界吧 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; A…...

有趣且重要的JS知识合集(18)浏览器实现前端录音功能

1、主题描述 兼容多个浏览器下的前端录音功能&#xff0c;实现六大录音功能&#xff1a; 1、开始录音 2、暂停录音 3、继续录音 4、结束录音 5、播放录音 6、上传录音 2、示例功能 初始状态&#xff1a; 开始录音&#xff1a; 结束录音&#xff1a; 录音流程 &#xf…...

面试官:聊聊你知道的跨域解决方案

跨域是开发中经常会遇到的一个场景&#xff0c;也是面试中经常会讨论的一个问题。掌握常见的跨域解决方案及其背后的原理&#xff0c;不仅可以提高我们的开发效率&#xff0c;还能在面试中表现的更加游刃有余。 因此今天就来和大家从前端的角度来聊聊解决跨域常见的几种方式。…...

SpringCloud五大核心组件

Consul 等&#xff0c;提供了搭建分布式系统及微服务常用的工具&#xff0c;如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性token、全局锁、选主、分布式会话和集群状态等&#xff0c;满足了构建微服务所需的所有解决方案。 服务发现——Netflix Eureka …...

Verilog HDL语言入门(二)

强烈建议用同步设计2.在设计时总是记住时序问题3.在一个设计开始就要考虑到地电平或高电平复位、同步或异步复位、上升沿或下降沿触发等问题&#xff0c;在所有模块中都要遵守它4.在不同的情况下用if和case&#xff0c;最好少用if的多层嵌套&#xff08;1层或2层比较合适&#…...

Simpleperf详细使用

一、Simpleperf介绍 Simpleperf是一个强大的命令行工具&#xff0c;它包含在NDK中&#xff0c;可以帮助我们分析应用的CPU性能。Simpleperf可以帮助我们找到应用的热点&#xff0c;而热点往往与性能问题相关&#xff0c;这样我们就可以分析修复热点源。 如果您更喜欢使用命令…...

【算法基础】二分图(染色法 匈牙利算法)

一、二分图 1. 染色法 一个图是二分图,当且仅当,图中不含奇数环。在判别一个图是否为二分图⑩,其实相当于染色问题,每条边的两个点必须是不同的颜色,一共有两种颜色,如果染色过程中出现矛盾,则说明不是二分图。 for i = 1 to n:if i 未染色DFS(i, 1); //将i号点染色未…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...