/* * Phihong_PsuCommObj.c * * Created on: 2019年7月2日 * Author: 7564 */ #include "Phihong_PsuCommObj.h" struct Current_cmd_Proc Psu_cmd={ 0, 0x02000200, 0x01000300, 0x01000400, 0x01000500, 0x01000600, 0x01000700, 0x01000800, 0x01000900, 0x02000A00, 0x02000B00, 0x01000C00, 0x02000F00, 0x02001000, 0x02001100, 0x02001200, 0x01001300, 0x02001400, 0x01001500, 0x01001600, 0x02001700, 0x01001800, 0x01001900, 0x01001A00, 0x02001B00, 0x0E001C00, }; //================================================ // Callback function //================================================ void GetPsuAddressReq(void *func) { get_psu_addr_req = func; } void RefreshStatus(void *func) { return_status = func; } void RefreshFWVersion(void *func) { return_fw_version = func; } void RefreshFanSpeed(void *func) { return_fan_speed = func; } void RefreshTemp(void *func) { return_temp = func; } void RefreshInputVol(void *func) { return_input_vol = func; } void RefreshGetOutput(void *func) { return_get_output = func; } void RefreshInputCur(void *func) { return_input_cur = func; } void RefreshHWVersion(void *func) { //return_hw_version = func; } void RefreshAvailableCap(void *func) { return_available_cap = func; } void RefreshAlarmNotify(void *func) { return_alarm_code = func; } void RefreshFaultNotify(void *func) { return_fault_code = func; } void RefreshStatusNotify(void *func) { return_status_code = func; } void RefreshSerialNumber(void *func) { return_get_serial_number = func; } void RefreshOutputPowerSwitch(void *func) { return_output_pow_switch = func; } //================================================ // CANBUS initialization //================================================ int InitCanBus() { int s0,nbytes; struct timeval tv; struct ifreq ifr0; struct sockaddr_can addr0; system("/sbin/ip link set can1 down"); system("/sbin/ip link set can1 type can bitrate 500000 restart-ms 100"); system("/sbin/ip link set can1 up"); s0 = socket(PF_CAN, SOCK_RAW, CAN_RAW); tv.tv_sec = 0; tv.tv_usec = 10000; if (setsockopt(s0, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) { #ifdef SystemLogMessage printf("Set SO_RCVTIMEO NG"); #endif } nbytes=40960; if (setsockopt(s0, SOL_SOCKET, SO_RCVBUF, &nbytes, sizeof(int)) < 0) { #ifdef SystemLogMessage printf("Set SO_RCVBUF NG"); #endif } nbytes=40960; if (setsockopt(s0, SOL_SOCKET, SO_SNDBUF, &nbytes, sizeof(int)) < 0) { #ifdef SystemLogMessage printf("Set SO_SNDBUF NG"); #endif } strcpy(ifr0.ifr_name, "can1" ); ioctl(s0, SIOCGIFINDEX, &ifr0); /* ifr.ifr_ifindex gets filled with that device's index */ addr0.can_family = AF_CAN; addr0.can_ifindex = ifr0.ifr_ifindex; bind(s0, (struct sockaddr *)&addr0, sizeof(addr0)); return s0; } //================================================ // Receive Cmd from canbus //================================================ void ReceiveDataFromCanBus() { int nbytes; struct can_frame frame; int intCmd; byte target, group, address; while(1) { memset(&frame, 0, sizeof(struct can_frame)); nbytes = read(CanFd, &frame, sizeof(struct can_frame)); if (nbytes > 0) { frame.can_id = frame.can_id & CAN_EFF_MASK; intCmd = (int) (frame.can_id & 0xFFFFFF00); target = (byte) (frame.can_id & 0x000000FF); group = (byte) (target >> 6); address = (byte) (target & 0x3F); switch (intCmd) { case ADDRESS_REQ: { byte phy_addr; char sn[7]; phy_addr = frame.data[0]; memcpy(sn, (char *)frame.data + 1, 7); get_psu_addr_req(phy_addr, sn); } break; case ACK_ADDRESS_ASSINGMENT: { } break; case ACK_STATUS: { return_status(group, address, ((int) frame.data[3] << 24) + ((int) frame.data[2] << 16) + ((int) frame.data[1] << 8) + (int) frame.data[0], ((int) frame.data[7] << 24) + ((int) frame.data[6] << 16) + ((int) frame.data[5] << 8) + (int) frame.data[4]); } break; case ACK_FIRMWARE_VERSION: { return_fw_version(group, address, frame.data[0], frame.data[1], frame.data + 2); } break; case ACK_FAN_SPEED: { return_fan_speed(group, address, ((short) frame.data[1] << 8) + (short) frame.data[0], ((short) frame.data[3] << 8) + (short) frame.data[2], ((short) frame.data[5] << 8) + (short) frame.data[4], ((short) frame.data[7] << 8) + (short) frame.data[6]); } break; case ACK_TEMPERATURE: { return_temp(group, address, frame.data[0], frame.data[1], frame.data[2], frame.data[3], frame.data[4], frame.data[5], frame.data[6]); } break; case ACK_PRESENT_INPUT_VOLTAGE: { return_input_vol(group, address, frame.data[0], ((short) frame.data[2] << 8) + (short) frame.data[1], ((short) frame.data[4] << 8) + (short) frame.data[3], ((short) frame.data[6] << 8) + (short) frame.data[5]); } break; case ACK_GET_PRESENT_OUTPUT: { return_get_output(group, address, (((short) frame.data[1] << 8) + (short) frame.data[0]), (((short) frame.data[3] << 8) + (short) frame.data[2])); } break; case ACK_GET_SERIAL_NUMBER: { return_get_serial_number(group, address, frame.data[0], frame.data + 1); } break; case ACK_COOLING_WATER_TEMP: { } break; case ACK_PRESENT_INPUT_CURRENT: { return_input_cur(group, address, (((short) frame.data[1] << 8) + (short) frame.data[0]), (((short) frame.data[3] << 8) + (short) frame.data[2]), (((short) frame.data[5] << 8) + (short) frame.data[4])); } break; case ACK_HARDWARE_VERSION: { } break; case ACK_PFC_OUTPUT_SWITCH: case ACK_LOG_SIZE: case ACK_LOG_BLOCK_CHECKSUM: case ACK_LOG_BLOCK_DATA: case ACK_CUSTOM_INFO_TRANSFER_SWITCH: case ACK_SET_FAN_SPEED: break; case ACK_AVAILABLE_CAP: { return_available_cap(group, address, (((short) frame.data[1] << 8) + (short) frame.data[0]), (((short) frame.data[3] << 8) + (short) frame.data[2])); } break; case ACK_OUTPUT_POWER_SWITCH: { return_output_pow_switch(group, address, frame.data[0]); } break; case ACK_SET_PRESENT_OUTPUT: { } break; case ACK_UPGRADE_REQ: { } break; case ACK_START_BLOCK_TRANS: { } break; case ACK_UPGRADE_FINISH: { } break; case CUSTOM_LOG_INFO: { } break; case ALARM_NOTIFICATION: { return_alarm_code(group, address, frame.data); } break; case FAULT_NOTIFICATION: { return_fault_code(group, address, ((int) frame.data[3] << 24) + ((int) frame.data[2] << 16) + ((int) frame.data[1] << 8) + (int) frame.data[0]); } break; case STATUS_NOTIFICATION: { return_status_code(group, address, frame.data[0], ((short) frame.data[2] << 8) + (short) frame.data[1], ((short) frame.data[4] << 8) + (short) frame.data[3]); } break; } } else { } usleep(10000); } } //================================================ // Private Function //================================================ int PackageIdCmd(int cmd) { return cmd | 0x80000000; } void SendCmdToPsu(int cmd, byte *data, byte dataLen) { struct can_frame frame; frame.can_id = cmd; frame.can_dlc = dataLen; memcpy(frame.data, data, dataLen); write(CanFd, &frame, sizeof(struct can_frame)); } //================================================ // API Function //================================================ bool InitialCommunication() { CanFd = InitCanBus(); if(CanFd < 0) { printf("Init can bus fail.\n"); return false; } recFork = fork(); if(recFork > 0) { ReceiveDataFromCanBus(); } else if(recFork > 0) { printf("fork fail\n"); } return true; } void PsuAddressAssignment(byte phy_addr, char *serial_number, byte real_addr, byte group) { int cmd = PackageIdCmd(Psu_cmd._address_assignment); byte data[8]; data[0] = (group << 6) + real_addr; memcpy(data + 1, serial_number, 7); SendCmdToPsu(cmd, data, sizeof(data)); } void GetStatus(byte group, byte address) { //printf("PSU_C_DLL : GetStatus. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_status + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetFwVersion(byte group, byte address, byte type) { //printf("PSU_C_DLL : GetFwVersion. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_fw_ver + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); data[0] = type; SendCmdToPsu(cmd, data, sizeof(data)); } void GetSerialNumber(byte group, byte address) { //printf("PSU_C_DLL : GetSerialNumber. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_serial_number + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetFanSpeed(byte group, byte address) { //printf("PSU_C_DLL : GetFanSpeed. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_fan_speed + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetTemperature(byte group, byte address) { //printf("PSU_C_DLL : GetTemperature. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_temperature + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetPresentInputVol(byte group, byte address) { //printf("PSU_C_DLL : GetPresentInputVol. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_present_input_vol + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetPresentOutput(byte group, byte address) { //printf("PSU_C_DLL : GetPresentOutput. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_present_output + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetPresentInputCurrent(byte group, byte address) { //printf("PSU_C_DLL : GetPresentInputCurrent. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_presnet_input_cur + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); SendCmdToPsu(cmd, data, sizeof(data)); } void GetAvailableCap(byte group, byte address, short _outputVol) { //printf("PSU_C_DLL : GetAvailableCap. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._get_available_cap + (group << 6) + address); byte data[8]; memset(data, 0x00, ARRAY_SIZE(data)); data[0] = _outputVol & 0xff; data[1] = (_outputVol >> 8) & 0xff; SendCmdToPsu(cmd, data, sizeof(data)); } void SetPresentOutput(byte group, byte address, short vol, short cur, unsigned short AvailableCur, byte derating) { //printf("PSU_C_DLL : SetPresentOutput. group = %x, address = %x \n", group, address); int cmd = PackageIdCmd(Psu_cmd._set_present_output + (group << 6) + address); byte data[8]; // 電壓 data[0] = vol & 0xff; data[1] = (vol >> 8) & 0xff; // 電流 (%) : 先算出總能夠輸出的電流當 100 %, 在與現在的希望輸出的電流比對,比出來的值為希望模塊輸出電流的比率 if (cur >= AvailableCur) cur = AvailableCur; short percent = ((float) cur / AvailableCur) * 10000; data[2] = percent & 0xff; data[3] = (percent >> 8) & 0xff; data[4] = derating; printf("vol = %d, tot_Amp = %d, need_cur = %d, percent = %d \n", vol, AvailableCur, cur, percent); SendCmdToPsu(cmd, data, sizeof(data)); } void EnableOutputPower(byte group, byte address, byte value) { int cmd = PackageIdCmd(Psu_cmd._switch_output_pow + (group << 6) + address); byte data[8]; //printf("cmd = %x \n", cmd); data[0] = value; SendCmdToPsu(cmd, data, sizeof(data)); }