meta-facebook/meta-lightning/recipes-lightning/front-paneld/files/front-paneld.c (220 lines of code) (raw):

/* * * Copyright 2015-present Facebook. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <syslog.h> #include <string.h> #include <pthread.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <time.h> #include <sys/time.h> #include <openbmc/pal.h> #include <openbmc/pal_sensors.h> #define BTN_MAX_SAMPLES 200 #define BTN_POWER_OFF 40 #define HB_TIMESTAMP_COUNT (60 * 60) #define POST_LED_DELAY_TIME 2 #define MIN_TRAY_VOL 0.3 struct _tray_last_status { uint8_t self; uint8_t peer; } tray_last_status; // Helper function for msleep void msleep(int msec) { struct timespec req; req.tv_sec = 0; req.tv_nsec = msec * 1000 * 1000; while(nanosleep(&req, &req) == -1 && errno == EINTR) { continue; } } // Thread for handling the Power and System Identify LED static void * id_led_handler() { int ret; char state[8]; while (1) { memset(state, 0, sizeof(state)); // Check if the user enabled system identify ret = pal_get_key_value("system_identify", state); if (ret) goto err; if (!strcmp(state, "on")) { // 0.9s ON pal_set_led(LED_DR_LED1, LED_ON); msleep(900); // 0.1s OFF pal_set_led(LED_DR_LED1, LED_OFF); msleep(100); continue; } else if (!strcmp(state, "off")) { printf("on\n"); pal_set_led(LED_DR_LED1, LED_ON); } err: sleep(1); } pthread_exit(NULL); } // Thread for handling the Enclosure LED static void * encl_led_handler() { int ret; uint8_t peb_hlth; uint8_t pdpb_hlth; uint8_t fcb_hlth; uint8_t bmc_hlth; while (1) { // Get health status for all the fru and then update the ENCL_LED status ret = pal_get_fru_health(FRU_PEB, &peb_hlth); if (ret) goto err; ret = pal_get_fru_health(FRU_PDPB, &pdpb_hlth); if (ret) goto err; ret = pal_get_fru_health(FRU_FCB, &fcb_hlth); if (ret) goto err; ret = pal_get_fru_health(BMC_HEALTH, &bmc_hlth); if (ret) goto err; if (!peb_hlth | !pdpb_hlth | !fcb_hlth | !bmc_hlth) pal_set_led(LED_ENCLOSURE, LED_N_ON); else pal_set_led(LED_ENCLOSURE, LED_N_OFF); err: sleep(1); } pthread_exit(NULL); } // Thread for monitoring debug card hotswap static void * debug_card_handler() { int i = 0; int bit_num = 0; int ret = 0; uint8_t current_tray_state = 0; uint8_t btn = 0; uint8_t pos = 0; uint8_t err_num = 0; char self_tray_name[16] = ""; char peer_tray_name[16] = ""; uint8_t peer_tray_pwr = 0; float peer_tray_vol = 0.0; uint8_t error_code_assert[ERROR_CODE_NUM * 8]; uint8_t error_code_array[ERROR_CODE_NUM] = {0}; int errCount = 0; int displayCount = 0; pal_write_error_code_file(0, ERR_DEASSERT); memset(&tray_last_status, 0, sizeof(tray_last_status)); /* Getting tray location information */ i = 0; //setting the retry limit to 3 ret = pal_get_tray_location(self_tray_name, sizeof(self_tray_name), peer_tray_name, sizeof(peer_tray_name), &peer_tray_pwr); while ((ret == -1) && (i < 3)){ sleep(1); ret = pal_get_tray_location(self_tray_name, sizeof(self_tray_name), peer_tray_name, sizeof(peer_tray_name), &peer_tray_pwr); syslog(LOG_WARNING, "%s(): pal_get_tray_location() failed", __func__); i++; } while (1) { /* Get self tray and peer tray location then set error code and record log.*/ current_tray_state = 0; if (!pal_self_tray_insertion(&current_tray_state)) { if (tray_last_status.self != current_tray_state) { tray_last_status.self = current_tray_state; if (current_tray_state) { pal_err_code_enable(ERR_CODE_SELF_TRAY_PULL_OUT); syslog(LOG_CRIT, "ASSERT: Self Tray (%s) Pulled-out", self_tray_name); } else { pal_err_code_disable(ERR_CODE_SELF_TRAY_PULL_OUT); syslog(LOG_CRIT, "DEASSERT: Self Tray (%s) Pulled-out", self_tray_name); } } } current_tray_state = 0; if (!pal_peer_tray_insertion(&current_tray_state)) { sensor_cache_read(FRU_FCB, peer_tray_pwr, &peer_tray_vol); if ((tray_last_status.peer != current_tray_state) && (peer_tray_vol > MIN_TRAY_VOL)) { tray_last_status.peer = current_tray_state; if (current_tray_state) { pal_err_code_enable(ERR_CODE_PEER_TRAY_PULL_OUT); syslog(LOG_CRIT, "ASSERT: Peer Tray (%s) Pulled-out", peer_tray_name); } else { pal_err_code_disable(ERR_CODE_PEER_TRAY_PULL_OUT); syslog(LOG_CRIT, "DEASSERT: Peer Tray (%s) Pulled-out", peer_tray_name); } } } pal_read_error_code_file(error_code_array); /* Read error code file for displaying error number on debug card*/ memset(error_code_assert, 0, ERROR_CODE_NUM * 8); errCount = 0; for(i = 0; i < ERROR_CODE_NUM; i++ ) { for(bit_num = 0; bit_num < 8; bit_num++ ) { if((( error_code_array[i] >> bit_num )&0x01 ) == 1) { *(error_code_assert + errCount) = i * 8 + bit_num; errCount++; } } } err_num = error_code_assert[displayCount]; displayCount++; if(displayCount >= errCount) displayCount = 0; // Check if UART channel button is pressed ret = pal_get_uart_chan_btn(&btn); if (ret) { goto debug_card_out; } if (!btn) { syslog(LOG_CRIT, "UART Channel button pressed\n"); // Wait for the button to be released for (i = 0; i < BTN_MAX_SAMPLES; i++) { ret = pal_get_uart_chan_btn(&btn); if (ret || !btn) { msleep(100); continue; } syslog(LOG_WARNING, "UART Channel button released\n"); break; } // handle error case if (i == BTN_MAX_SAMPLES) { syslog(LOG_WARNING, "UART Channel button seems to stuck for long time\n"); goto debug_card_out; } // Get the current position for the UART ret = pal_get_uart_chan(&pos); if (ret) { goto debug_card_out; } // Toggle the UART position ret = pal_set_uart_chan(!pos); if (ret) { goto debug_card_out; } // Display Post code on UART button press event if (pal_set_debug_card_led(pos)) syslog(LOG_WARNING, "%s(): pal_set_debug_card_led() failed", __func__); sleep(POST_LED_DELAY_TIME); } if (pal_set_debug_card_led(err_num)) syslog(LOG_WARNING, "%s(): pal_set_debug_card_led() failed", __func__); debug_card_out: sleep(POST_LED_DELAY_TIME); } pthread_exit(NULL); } int main (int argc, char * const argv[]) { pthread_t tid_debug_card; pthread_t tid_encl_led; pthread_t tid_id_led; if (pthread_create(&tid_debug_card, NULL, debug_card_handler, NULL) < 0) { syslog(LOG_WARNING, "pthread_create for debug card error\n"); exit(1); } if (pthread_create(&tid_encl_led, NULL, encl_led_handler, NULL) < 0) { syslog(LOG_WARNING, "pthread_create for encl led error\n"); exit(1); } if (pthread_create(&tid_id_led, NULL, id_led_handler, NULL) < 0) { syslog(LOG_WARNING, "pthread_create for system identify led error\n"); exit(1); } pthread_join(tid_debug_card, NULL); pthread_join(tid_encl_led, NULL); pthread_join(tid_id_led, NULL); return 0; }