/* Includes ------------------------------------------------------------------*/ #include "config.h" #include "interlock.h" #include "Utils.h" #include #include #include "trigutil.h" /* Private typedef -----------------------------------------------------------*/ typedef unsigned char GROUP_ID; typedef unsigned char DOOR_ID; typedef enum{ GROUP_ENABLED, GROUP_WAIT_INTERLOCKED, GROUP_INTERLOCKED, GROUP_TIMED_INTERLOCK, GROUP_STATE_LAST }GROUP_STATE; typedef enum{ LOCK_OPENNED, DOOR_NOT_OPENNED, DOOR_OPENNED, LAST_DOOR_IN_THIS_GROUP_CLOSED, ONE_SECOND_PASSED, GROUP_TIME_OUT_ELAPSED, GROUP_EVENT_LAST }GROUP_EVENT; typedef struct{ GROUP_STATE state; u16 time_till_enabled; u8 number_of_openned_doors; }GROUP_STATUS; typedef struct{ u8 panel_num; u8 output_num; }OUTPUT_FOR_DOOR; typedef void(*FuncPtr)(GROUP_ID group_id, s32 aParameter); typedef struct { GROUP_STATE nextState; FuncPtr transition_Function; }STATE_TRANSITION_MATRIX_ELEMENT; /* Private define ------------------------------------------------------------*/ #define MAX_NUMBER_OF_DOORS 74 #define MAX_NUMBER_OF_DOORS_IN_A_GROUP 5 #define MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF 5 #define NO_DOOR 0xFF #define NO_GROUP 0xFF /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ GROUP_ID the_groups_that_this_door_is_part_of[MAX_NUMBER_OF_DOORS][MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF]; DOOR_ID the_doors_that_are_part_of_this_group[MAX_NUMBER_OF_GROUPS][MAX_NUMBER_OF_DOORS_IN_A_GROUP];// GROUP--> DOORS u16 timeout_for_this_group_from_axtraxNG[MAX_NUMBER_OF_GROUPS]; OUTPUT_FOR_DOOR output_for_door[MAX_NUMBER_OF_DOORS]; GROUP_STATUS group_status[MAX_NUMBER_OF_GROUPS]; /* Private function prototypes -----------------------------------------------*/ void ClearSemaphoreRedLedForGroup(GROUP_ID group_id,s32 not_in_use); void SetTimerForGroup(GROUP_ID group_id,s32 not_in_use); void UpdateGroupStateMachine(GROUP_ID group_id, GROUP_EVENT event); void ActiveRelevantLED(GROUP_ID group_id, s32 event); void UpdateTime(GROUP_ID group_id, s32 aParameter); const STATE_TRANSITION_MATRIX_ELEMENT group_stm[GROUP_STATE_LAST][GROUP_EVENT_LAST] = { // LOCK_OPENNED (ELECTRICITY) DOOR_NOT_OPENNED DOOR_OPENNED (PHISICAL) LAST_DOOR_IN_THIS_GROUP_CLOSED, ONE_SECOND_PASSED, GROUP_TIME_OUT_ELAPSED, /* GROUP_ENABLED */ {{GROUP_WAIT_INTERLOCKED, ActiveRelevantLED},{GROUP_ENABLED,ClearSemaphoreRedLedForGroup},{GROUP_INTERLOCKED, ActiveRelevantLED}, {GROUP_ENABLED,NULL }, {GROUP_ENABLED, NULL}, {GROUP_ENABLED,NULL }}, /* GROUP_WAIT_INTERLOCKED */ {{GROUP_WAIT_INTERLOCKED, ActiveRelevantLED},{GROUP_ENABLED,ClearSemaphoreRedLedForGroup},{GROUP_INTERLOCKED, ActiveRelevantLED}, {GROUP_ENABLED,NULL }, {GROUP_WAIT_INTERLOCKED, NULL}, {GROUP_ENABLED,NULL }}, /* GROUP_INTERLOCKED */ {{GROUP_INTERLOCKED, NULL}, {GROUP_INTERLOCKED, NULL}, {GROUP_INTERLOCKED, NULL}, {GROUP_TIMED_INTERLOCK,SetTimerForGroup }, {GROUP_INTERLOCKED, NULL}, {GROUP_INTERLOCKED,NULL }}, /* GROUP_TIMED_INTERLOCK */ {{GROUP_INTERLOCKED, NULL}, {GROUP_INTERLOCKED, NULL}, {GROUP_INTERLOCKED, NULL}, {GROUP_TIMED_INTERLOCK,NULL}, {GROUP_TIMED_INTERLOCK, UpdateTime}, {GROUP_ENABLED,ClearSemaphoreRedLedForGroup}} }; u8 AbsolutNumberDoor(u8 panel_num,u8 door) { u8 absolut_door = NO_DOOR; if(panel_num <= MAX_PANELS){ absolut_door = (panel_num * 4) + door; if(panel_num > MAIN_PANEL){ absolut_door += 6; } } return absolut_door; } void EraseInterlockGroup(u8 group_id) { u8 door_id,group_index; for(door_id = 0;door_id < MAX_NUMBER_OF_DOORS;door_id ++){ for(group_index = 0;group_index < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF;group_index ++){ if(the_groups_that_this_door_is_part_of[door_id][group_index] == group_id){ the_groups_that_this_door_is_part_of[door_id][group_index] = NO_DOOR; } } } memset(the_doors_that_are_part_of_this_group[group_id],NO_GROUP,MAX_NUMBER_OF_DOORS_IN_A_GROUP); timeout_for_this_group_from_axtraxNG[group_id] = 0; } void EraseAllInterlockGroups(void) { u8 group; memset(the_groups_that_this_door_is_part_of,NO_DOOR,sizeof(the_groups_that_this_door_is_part_of)); memset(the_doors_that_are_part_of_this_group,NO_GROUP,sizeof(the_doors_that_are_part_of_this_group)); memset(output_for_door,NO_DOOR,sizeof(output_for_door)); for(group = 0;group < MAX_NUMBER_OF_GROUPS;group ++){ timeout_for_this_group_from_axtraxNG[group] = 0; group_status[group].state = GROUP_ENABLED;//each group is initialized with default valu group_status[group].time_till_enabled = 0x00; group_status[group].number_of_openned_doors = 0x00; } } //each udate from AxTraxNG do this function. In addition once the 825 start to work after power on reset void UpdateInterlockDatabaseRAM(u8 group_id) { u8 temp[(MAX_NUMBER_OF_DOORS_IN_A_GROUP * 4) + 2],i,group_index,door; if(group_id < MAX_NUMBER_OF_GROUPS){ EraseInterlockGroup(group_id); DB_Read(FLASH_INTERLOCK_GROUP_START + (NUMBER_BYTES_INTERLOCK_GROUP_PACKET * group_id),temp,sizeof(temp)); for(i = 0;i < sizeof(temp) - 2;i += 4){ the_doors_that_are_part_of_this_group[group_id][i / 4] = AbsolutNumberDoor(temp[i] - 1,temp[i + 1]); } for(i = 0;i < MAX_NUMBER_OF_DOORS_IN_A_GROUP;i ++){ door = the_doors_that_are_part_of_this_group[group_id][i]; if(door < MAX_NUMBER_OF_DOORS){//valid door for(group_index = 0;group_index < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF;group_index ++){ if(the_groups_that_this_door_is_part_of[door][group_index] == group_id){ break; } } if(group_index >= MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF){ for(group_index = 0;group_index < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF;group_index ++){ if(the_groups_that_this_door_is_part_of[door][group_index] == NO_GROUP){ the_groups_that_this_door_is_part_of[door][group_index] = group_id; break; } } } } else{ } } for(i = 0;i < sizeof(temp) - 2;i += 4){ door = AbsolutNumberDoor(temp[i] - 1,temp[i + 1]); if(door != NO_DOOR){ output_for_door[door].panel_num = temp[i + 2] - 1; output_for_door[door].output_num = temp[i + 3]; } } DB_Read(FLASH_INTERLOCK_GROUP_START + (NUMBER_BYTES_INTERLOCK_GROUP_PACKET * group_id) + (NUMBER_BYTES_INTERLOCK_GROUP_PACKET - 2),temp,2); timeout_for_this_group_from_axtraxNG[group_id] = temp[0] * 0x100 + temp[1]; if(timeout_for_this_group_from_axtraxNG[group_id] > 610){//10 min. delay timeout_for_this_group_from_axtraxNG[group_id] = 0; } group_status[group_id].state = GROUP_ENABLED;//each group is initialized with default valu group_status[group_id].time_till_enabled = 0x00; group_status[group_id].number_of_openned_doors = 0x00; } } void InitInterlockGroup(void) { u8 group_id; memset(the_groups_that_this_door_is_part_of,NO_DOOR,sizeof(the_groups_that_this_door_is_part_of)); memset(the_doors_that_are_part_of_this_group,NO_GROUP,sizeof(the_doors_that_are_part_of_this_group)); memset(output_for_door,NO_DOOR,sizeof(output_for_door)); for(group_id = 0;group_id < MAX_NUMBER_OF_GROUPS;group_id ++){ UpdateInterlockDatabaseRAM(group_id); } } void OneSecondPassedInterlock(void) { //update all groups that one second passed GROUP_ID group_id; for(group_id = 0;group_id < MAX_NUMBER_OF_GROUPS;group_id ++){ UpdateGroupStateMachine(group_id,ONE_SECOND_PASSED); } } void UpdateTime(GROUP_ID group_id,s32 aParameter) { if(group_status[group_id].time_till_enabled <= 1){ group_status[group_id].time_till_enabled = 0; UpdateGroupStateMachine(group_id,GROUP_TIME_OUT_ELAPSED); } else{ group_status[group_id].time_till_enabled --; } } void SetTimerForGroup(GROUP_ID group_id,s32 not_in_use) { group_status[group_id].time_till_enabled = timeout_for_this_group_from_axtraxNG[group_id]; } void ReportDoorOpenned(DOOR_ID door_id) { GROUP_ID group_id,group_id_index = 0; // find all the groups that this door is part of and update their status & state machine group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; while(group_id < MAX_NUMBER_OF_GROUPS){ group_status[group_id].number_of_openned_doors ++; UpdateGroupStateMachine(group_id,DOOR_OPENNED); group_id_index ++; group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; // get next group of that door } } void ReportDoorClosed(DOOR_ID door_id) { GROUP_ID group_id,group_id_index = 0; // find all the groups that this door is part of and update their state machine group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; while(group_id < MAX_NUMBER_OF_GROUPS){ if(group_status[group_id].number_of_openned_doors <= 1){ // the last door group_status[group_id].number_of_openned_doors = 0; UpdateGroupStateMachine(group_id,LAST_DOOR_IN_THIS_GROUP_CLOSED); } else{ group_status[group_id].number_of_openned_doors --; } group_id_index ++; group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; //get next group } } bool CanOpenDoor(DOOR_ID door_id,u8 check_state_machine) { GROUP_ID group_id,group_id_index = 0; GROUP_ID group_array[MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF],i; bool can_open = TRUE; memset(group_array,NO_GROUP,sizeof(group_array)); i = 0; // for each group that the door is part of -- look if one of the group disables this door. group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; while(group_id_index < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF){//MAX_NUMBER_OF_GROUPS){ if(group_id != NO_GROUP){ if(group_status[group_id].state != GROUP_ENABLED){ can_open = FALSE; break; } else{ group_array[i ++] = group_id; } } group_id_index ++; group_id = the_groups_that_this_door_is_part_of[door_id][group_id_index]; // bring the next group for that door } if(can_open == TRUE){ if(check_state_machine){ for(i = 0;i < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF;i ++){ if(group_array[i] != NO_GROUP){ UpdateGroupStateMachine(group_array[i],LOCK_OPENNED); } } } } return can_open;// if no limitation was found then allow open } void ActiveRelevantLED(GROUP_ID group_id,s32 event) { u8 panel_num,output_num,i,door; for(i = 0;i < MAX_NUMBER_OF_DOORS_IN_A_GROUP;i ++){ door = the_doors_that_are_part_of_this_group[group_id][i]; if(door != NO_DOOR){ if(output_for_door[door].panel_num < MAX_PANELS && output_for_door[door].output_num < MAX_OUTPUTS){ panel_num = output_for_door[door].panel_num; output_num = output_for_door[door].output_num; ChangeOutState(panel_num,0x15,output_num,1);//start } } } } void DeActiveRelevantLED(DOOR_ID door_id) { u8 panel_num,output_num; if(output_for_door[door_id].panel_num < MAX_PANELS && output_for_door[door_id].output_num < MAX_OUTPUTS){ panel_num = output_for_door[door_id].panel_num; output_num = output_for_door[door_id].output_num; ChangeOutState(panel_num,0x16,output_num,1);//stop } } void ClearSemaphoreRedLedForGroup(GROUP_ID group_id,s32 not_in_use) { // for all doors in that group: if the doors can be open then change the led to "OK entrance (clear led) DOOR_ID door_id,door_id_index = 0; static DOOR_ID saved_door[MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF] = {NO_DOOR,NO_DOOR,NO_DOOR,NO_DOOR,NO_DOOR};//NO_DOOR,NO_DOOR,NO_DOOR}; static DOOR_ID saved_door_index; // find all the doors in that group that this door is part of and update their state machine door_id = the_doors_that_are_part_of_this_group[group_id][door_id_index]; while(door_id < MAX_NUMBER_OF_DOORS){ if(CanOpenDoor(door_id,0)){ DeActiveRelevantLED(door_id); } else{ saved_door[saved_door_index ++] = door_id; if(saved_door_index >= MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF){ saved_door_index = 0; } } door_id_index ++; door_id = the_doors_that_are_part_of_this_group[group_id][door_id_index]; } door_id_index = 0; while(door_id_index < sizeof(saved_door)){ if(saved_door[door_id_index] != NO_DOOR){ if(CanOpenDoor(saved_door[door_id_index],0)){ DeActiveRelevantLED(saved_door[door_id_index]); saved_door[door_id_index] = NO_DOOR; } } door_id_index ++; } } void UpdateGroupStateMachine(GROUP_ID group_id, GROUP_EVENT event) { GROUP_STATE current_state = group_status[group_id].state; GROUP_STATE next_state = group_stm[current_state][event].nextState; FuncPtr transition_function = group_stm[current_state][event].transition_Function; // do the transition group_status[group_id].state = next_state; if(transition_function != NULL){ // activate the transion function transition_function(group_id,event); } } u8 IsDoorMonitorInput(u8 panel_num,u8 input) { u8 door_monitor[12] = {NO_DOOR,0,NO_DOOR,1,NO_DOOR,2,NO_DOOR,3,NO_DOOR,4,NO_DOOR,5}; u8 value = NO_DOOR; if(panel_num == MAIN_PANEL || activity_ext[panel_num] == D805){ value = door_monitor[input]; if((panel[panel_num].main_type & 0x03) == TWO_READERS_PER_DOOR){ if(value != NO_DOOR){ value /= 2; } } } return value; } void DoorStatusFn(u8 panel_num,u8 input,u8 status) { u8 door; door = IsDoorMonitorInput(panel_num,input); if(panel[panel_num].Input[input].Type % 2){//NC if(status == CInputOpen){//input-door is open if(door != NO_DOOR){//no door monitor door = AbsolutNumberDoor(panel_num,door); if(door != NO_DOOR){//no door in the interlock database ReportDoorOpenned(door); } } } else{//input-door is close if(door != NO_DOOR){//no door monitor door = AbsolutNumberDoor(panel_num,door); if(door != NO_DOOR){//no door in the interlock database ReportDoorClosed(door); } } } } else{//NO if(status == CInputClosed){//input-door is open if(door != NO_DOOR){//no door monitor door = AbsolutNumberDoor(panel_num,door); if(door != NO_DOOR){//no door in the interlock database ReportDoorOpenned(door); } } } else{//input-door is close if(door != NO_DOOR){//no door monitor door = AbsolutNumberDoor(panel_num,door); if(door != NO_DOOR){//no door in the interlock database ReportDoorClosed(door); } } } } } u8 TestOldInterlock(u8 panel_num,u8 Door_) { u8 temp_door,temp_input; if((0x01 << Door_) & panel[panel_num].Interlock){ for(temp_door = 0;temp_door < panel[panel_num].num_of_doors;temp_door ++){ if(temp_door == Door_){ continue; } if((0x01 << temp_door) & panel[panel_num].Interlock){ //test dor monitor inputs if((panel[panel_num].main_type & 0x03) == TWO_READERS_PER_DOOR){ temp_input = (temp_door * 4) + 1; } else{ temp_input = (temp_door * 2) + 1; } if(panel[panel_num].Input[temp_input].Type % 2){ if(panel[panel_num].Input[temp_input].Status != CInputClosed){ return 1; } } else if(!(panel[panel_num].Input[temp_input].Type % 2)){//if(Input[Ind].Type == Z_InType_NormalOpen){ if(panel[panel_num].Input[temp_input].Status != CInputOpen){ return 1; } } //test lock open if((panel[panel_num].main_type & 0x03) == TWO_READERS_PER_DOOR){ temp_input = temp_door * 2; } else{ temp_input = temp_door; } if(panel[panel_num].LogicalBitsDoorOutput & (1 << temp_input)){//temp_input replace the number of output return 1; } } } } return 0; } bool TestInterlock(u8 panel_num,u8 door) { bool dont_open = FALSE;//FALSE - can open,TRUE - don't open have interlock u8 temp; DB_Read(PANELS_USERS_START + (panel_num * EACH_PANEL_USER_OFFSET) + USER_CONDITIONS_OFFSET + ((BYTES_PER_USER * (panel[panel_num].Door[door].VarDoorData.CodeNumber - 1)) + FLASH_USER_FLAGS_OFFSET),&temp,1); if(!(temp & Z_InterlockImmunity)){//no immunity to the user if(TestOldInterlock(panel_num,door)){ dont_open = TRUE; } else{ // have to convert the door number door = AbsolutNumberDoor(panel_num,door); if(!CanOpenDoor(door,1)){ dont_open = TRUE; } } } return dont_open; } void IsInterlockDoorOpenned(u8 panel_num,u8 door) { GROUP_ID group_id,group_id_index = 0; door = AbsolutNumberDoor(panel_num,door); // for each group that the door is part of -- look if one of the group disables this door. group_id = the_groups_that_this_door_is_part_of[door][group_id_index]; while(group_id_index < MAX_NUMBER_OF_GROUP_THAT_A_DOOR_IS_PART_OF){//MAX_NUMBER_OF_GROUPS){ if(group_id != NO_GROUP){ if(group_status[group_id].state == GROUP_WAIT_INTERLOCKED){ UpdateGroupStateMachine(group_id,DOOR_NOT_OPENNED); } } group_id_index ++; group_id = the_groups_that_this_door_is_part_of[door][group_id_index]; // bring the next group for that door } }