void PAGE_SwitchAssignInit(int page) { (void)page; PAGE_SetActionCB(_action_cb); PAGE_SetModal(0); PAGE_RemoveAllObjects(); refresh_switches(); PAGE_ShowHeader(_tr("Press ENT to change")); GUI_CreateScrollable(&gui->scrollable, 0, ITEM_HEIGHT + 1, LCD_WIDTH, LCD_HEIGHT - ITEM_HEIGHT -1, ITEM_SPACE, SWITCHFUNC_LAST, row_cb, getobj_cb, NULL, NULL); GUI_SetSelected(GUI_ShowScrollableRowOffset(&gui->scrollable, 0)); }
//responsible for displaying all the necessary information to the screen many times per second. //runs at fairly low priority by design. //output includes: // * switch states // * sensor triggering timestamps // * current positions of up to 3 trains relative to parts of the track // almost never blocks, just keeps spinning when nothing higher-priority needs to run void display_server(void){ TrainState trains[MAX_TRAINS]; int train_count = 0; SensorState sensors[SENSOR_HISTORY_LEN]; int sensor_start = 0; int sensor_len = 0; SwitchState switches[18+4]; int active = 0; int i; // initialze switches 1-18 for(i=0; i < 18; i++){ switches[i].number = i+1; switches[i].state = '?'; } // and switches 153-156 for(i=0; i < 4; i++){ switches[i+18].number = i+153; switches[i+18].state = '?'; } RegisterAs("displayserver"); int clockserverTid = WhoIs("clockserver"); if(clockserverTid < 0){ bwprintf(COM2, "Display server got tid %d for clocckserver\n\r", clockserverTid); Halt(); } Create(PRIORITY_MID, &display_notifier); Create(PRIORITY_MID, &display_sensor_notifier); int tid, len; MsgPrintf msg; int printf_col = 0; // now we can start drawing and receiving messages in a loop. FOREVER { len = Receive(&tid, (char*) &msg, sizeof(msg)); if(len > 0){ // I never have a useful Reply, so Reply immediately Reply(tid, NULL, 0); switch(msg.type){ case MSG_DISPLAY_REGISTER: ; // add a train with the provided number and speed 0 // if this is the first train, initialize the display if(train_count == 0){ clear_screen(); initialize_scrolling(); refresh_switches(switches); refresh_sensors(sensors, sensor_start, sensor_len); active = 1; } MsgRegister *msgReg = (MsgRegister*) &msg; trains[train_count].number = msgReg->train; trains[train_count].speed = 0; trains[train_count].route_len = 0; train_count++; break; case MSG_DISPLAY_DEREGISTER: ; // look up the train in the trains array, and pack the ones after it // special case for the last train msgReg = (MsgRegister*) &msg; if(train_count == 1){ //clear_screen(); restore_scrolling(); move_cursor(SCREEN_BOTTOM, 1); active = 0; train_count = 0; } else if(train_count == 0){ // do nothing } else { int i = 0; for(i=0; i < train_count; i++){ if(trains[i].number == msgReg->train){ break; } } // if we find the train, shift the rest of the array down if(i < train_count){ for(i=i+1; i < train_count; i++){ //copy to the previous one trains[i-1] = trains[i]; } train_count--; } } break; case MSG_DISPLAY_SPEED: ; // update the given train's speed MsgSpeed *msgSpeed = (MsgSpeed*) &msg; // flip through my trains for this number for(i = 0; i < train_count; i++){ if(trains[i].number == msgSpeed->train){ trains[i].speed = msgSpeed->speed; break; } } // will be redisplayed below break; case MSG_DISPLAY_SWITCH: ; MsgSwitch *msgSwitch = (MsgSwitch*) &msg; if(msgSwitch->number <= 18){ switches[msgSwitch->number-1].state = msgSwitch->state; } else { switches[msgSwitch->number-153+18].state = msgSwitch->state; } if(active){ refresh_switches(switches); } break; case MSG_DISPLAY_ROUTE: ; // somewhat more complicated. copy the route for the given train // first find the train index MsgRouteSegment *msgRoute = (MsgRouteSegment*) &msg; for(i = 0; i < train_count; i++){ if(trains[i].number == msgRoute->train){ trains[i].route_len = msgRoute->route_len; int j; for(j = 0; j < msgRoute->route_len; j++){ trains[i].route[j] = msgRoute->route[j]; } } } break; case MSG_SENSOR_CLIENT: ; // message from the sensor server // work through the array from the sensor server, and update my list of sensors // remember that the sensors array starts at start and start gets decremented MsgSensorResponse *msgResp = (MsgSensorResponse*) &msg; int timestamp = Time(clockserverTid); for(i = 0; i < msgResp->length; i++){ sensor_start--; if(sensor_start < 0) sensor_start = SENSOR_HISTORY_LEN-1; if(sensor_len < SENSOR_HISTORY_LEN) sensor_len++; getSensorName(msgResp->triggered[i], &(sensors[sensor_start])); sensors[sensor_start].time = timestamp; } if(active && msgResp->length > 0){ refresh_sensors(sensors, sensor_start, sensor_len); } break; case MSG_DISPLAY_PRINTF: ; move_cursor(SCREEN_BOTTOM, printf_col); switch(msg.argc){ case 0: aprintf(COM2, msg.format); break; case 1: aprintf(COM2, msg.format, msg.argv[0]); break; case 2: aprintf(COM2, msg.format, msg.argv[0], msg.argv[1]); break; case 3: aprintf(COM2, msg.format, msg.argv[0], msg.argv[1], msg.argv[2]); break; case 4: aprintf(COM2, msg.format, msg.argv[0], msg.argv[1], msg.argv[2], msg.argv[3]); break; case 5: aprintf(COM2, msg.format, msg.argv[0], msg.argv[1], msg.argv[2], msg.argv[3], msg.argv[4]); break; default: aprintf(COM2, "Bad argc: %d\n\r", msg.argc); break; } int len = strlen(msg.format); if(msg.format[len-1] == '\n' || msg.format[len-1] == '\r'){ printf_col = 0; } else { printf_col += len; } break; case MSG_TICK: ; // display the train position // very crude for now. also only handling one train if(active){ int i; int base_row; for(i = 0; i < train_count; i++){ base_row = TRAIN_TOP + TRAIN_SIZE*i; move_and_clear(base_row, TRAIN_LEFT); aprintf(COM2, "Train %2d: ", trains[i].number); move_and_clear(base_row+1, TRAIN_LEFT); aprintf(COM2, "Speed: %2d ", trains[i].speed); if(trains[i].route_len > 0){ SensorState ss; Sensor *s = (Sensor*) (trains[i].route[0]); getSensorName(s->alignment == 'F' ? s->forward_num : s->backward_num, &ss); move_and_clear(base_row+2, TRAIN_LEFT); aprintf(COM2, "Current sensor:\t%c%2d ", ss.module, ss.number); s = (Sensor*) (trains[i].route[ trains[i].route_len-1 ]); getSensorName(s->alignment == 'F' ? s->forward_num : s->backward_num, &ss); move_and_clear(base_row+3, TRAIN_LEFT); aprintf(COM2, "Next sensor:\t%c%2d ", ss.module, ss.number); } else { move_and_clear(base_row+2, TRAIN_LEFT); aprintf(COM2, "No route supplied."); } } } break; default: ; aprintf(COM2, "Display server: bogus type %d\n\r", msg.type); } } } }