void EVENT_USB_Device_Connect(void) { DEBUGF(DBG_ALL, "usbcon\n"); board_set_status(STATUS_CONNECTING); doDeviceReset = false; usb_connected = true; }
/* Create our board and return a pointer to our object */ Board *board_init(int height, int width) { Board *board = malloc(sizeof(Board)); board->height = height; board->width = width; board->count_empty = 0; board->count_loyalist = 0; board->count_rebel = 0; board->count_empty = height * width; /* We allocate enough memory for the cells in our board * we store a simple array of pointers and use basic arithmetic two get the correct cell */ board->cells = (Cell *)malloc(board->height * board->width * sizeof(Cell)); board->stack_a = stack_init(); board->stack_b = stack_init(); /* We set the initial values of the cells in our board * on the first pass we just create an empty board */ for (int row = 0; row < board->height; row++) { for (int col = 0; col < board->width; col++) { Cell *cell = board_get_cell(board, row, col); cell->row = row; cell->col = col; cell->loyals = 0; cell->rebels = 0; cell->color = 0; cell->degree = 0; cell->empty = 4; cell->status = 0; // Initial values of the corners if ((!row && !col) || (!row && col + 1 == board->width) || (row + 1 == board->height && !col) || (row + 1 == board->height && col + 1 == board->width)) { cell->empty = 2; } //values of the edges - corners else if (!row || !col || row + 1 == board->height || col + 1 == board->width) { cell->empty = 3; } else { stack_push(board->stack_b, cell); } } } for (int row = 0; row < board->height; row++) { for (int col = 0; col < board->width; col++) { if (!row || !col || row + 1 == board->height || col + 1 == board->width) { board_set_status(board, row, col, 1); } } } return board; }
int main(void) { /* * Setup the CPU and USB configuration. Wait after power-on for VBUS. * This is to handle the case where we are being powered from the * IEC bus through the IOs without a USB connection. Nate analyzed the * time we run until brownout here and it defaults to 65 ms due to the * CKSEL/SUT fuse. * * Instead of just a delay, we can wait for VBUS to be active and then * be sure USB is connected. This works even when we can't use the * brown-out detector. On the USBKEY, the BOD can only be 2.6V or 3.4V * but it runs at 3.3V. */ cpu_init(); USB_Init(); while (!usb_connected) wdt_reset(); // Indicate device not ready board_init(); board_set_status(STATUS_INIT); // If a CBM 153x tape drive is attached, detect it and enable tape mode. // If any IEC/IEEE drives are attached, detect them early. // This leaves the IO pins in the proper state to allow them to come // out of reset until we're ready to access them. cbm_init(); /* * Process bulk transactions as they appear. Control requests are * handled separately via IRQs. */ for (;;) { wdt_reset(); while (device_running) { // Check for and process any commands coming in on the bulk pipe. USB_BulkWorker(); /* * Do periodic tasks each command. If we found the device was in * a stalled state, reset it before the next command. */ if (!TimerWorker()) doDeviceReset = false; } // TODO: save power here when device is not running // Wait for device to be reconnected to USB while (!usb_connected) wdt_reset(); } }
void EVENT_USB_Device_Disconnect(void) { DEBUGF(DBG_ALL, "usbdiscon\n"); // Halt the main() command loop and indicate we are not configured usb_connected = false; device_running = false; board_set_status(STATUS_INIT); }
void EVENT_USB_Device_UnhandledControlRequest(void) { uint8_t replyBuf[XUM_DEVINFO_SIZE]; int8_t len; /* * Ignore non-class requests. We also only handle commands * that don't transfer any data or just transfer it into the host. */ if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_TYPE) != REQTYPE_CLASS) { DEBUGF(DBG_ERROR, "bad ctrl req %x\n", USB_ControlRequest.bmRequestType); return; } // Process the command and get any returned data memset(replyBuf, 0, sizeof(replyBuf)); len = usbHandleControl(USB_ControlRequest.bRequest, replyBuf); if (len == -1) { DEBUGF(DBG_ERROR, "ctrl req err\n"); board_set_status(STATUS_ERROR); return; } // Control request was handled so ack it to allow another Endpoint_ClearSETUP(); // Send data back to host and finalize the status phase if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_DIRECTION) == REQDIR_DEVICETOHOST) { Endpoint_Write_Control_Stream_LE(replyBuf, len); Endpoint_ClearOUT(); } else { while (!Endpoint_IsINReady()) ; Endpoint_ClearIN(); } }
void EVENT_USB_Device_ConfigurationChanged(void) { DEBUGF(DBG_ALL, "usbconfchg\n"); // Clear out any old configuration before allocating USB_ResetConfig(); /* * Setup and enable the two bulk endpoints. This must be done in * increasing order of endpoints (3, 4) to avoid fragmentation of * the USB RAM. */ Endpoint_ConfigureEndpoint(XUM_BULK_IN_ENDPOINT, EP_TYPE_BULK, ENDPOINT_DIR_IN, XUM_ENDPOINT_BULK_SIZE, ENDPOINT_BANK_DOUBLE); Endpoint_ConfigureEndpoint(XUM_BULK_OUT_ENDPOINT, EP_TYPE_BULK, ENDPOINT_DIR_OUT, XUM_ENDPOINT_BULK_SIZE, ENDPOINT_BANK_DOUBLE); // Indicate USB connected and ready to start event loop in main() board_set_status(STATUS_READY); device_running = true; }
static bool USB_BulkWorker() { uint8_t cmdBuf[XUM_CMDBUF_SIZE], statusBuf[XUM_STATUSBUF_SIZE]; int8_t status; /* * If we are not connected to the host or a command has not yet * been sent, no more processing is required. */ if (USB_DeviceState != DEVICE_STATE_Configured) return false; Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT); if (!Endpoint_IsReadWriteAllowed()) return false; #ifdef DEBUG // Dump the status of both endpoints before getting the command Endpoint_SelectEndpoint(XUM_BULK_IN_ENDPOINT); DEBUGF(DBG_INFO, "bsti %x %x %x %x %x %x %x %x\n", Endpoint_GetCurrentEndpoint(), Endpoint_BytesInEndpoint(), Endpoint_IsEnabled(), Endpoint_IsReadWriteAllowed(), Endpoint_IsConfigured(), Endpoint_IsINReady(), Endpoint_IsOUTReceived(), Endpoint_IsStalled()); Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT); DEBUGF(DBG_INFO, "bsto %x %x %x %x %x %x %x %x\n", Endpoint_GetCurrentEndpoint(), Endpoint_BytesInEndpoint(), Endpoint_IsEnabled(), Endpoint_IsReadWriteAllowed(), Endpoint_IsConfigured(), Endpoint_IsINReady(), Endpoint_IsOUTReceived(), Endpoint_IsStalled()); #endif // Read in the command from the host now that one is ready. if (!USB_ReadBlock(cmdBuf, sizeof(cmdBuf))) { board_set_status(STATUS_ERROR); return false; } // Allow commands to leave the extended status untouched memset(statusBuf, 0, sizeof(statusBuf)); /* * Decode and process the command. * usbHandleBulk() stores its extended result in the output buffer, * up to XUM_STATUSBUF_SIZE. * * Return values: * >0: completed ok, send the return value and extended status * 0: completed ok, don't send any status * -1: error, no status */ status = usbHandleBulk(cmdBuf, statusBuf); if (status > 0) { statusBuf[0] = status; USB_WriteBlock(statusBuf, sizeof(statusBuf)); } else if (status < 0) { DEBUGF(DBG_ERROR, "usbblk err\n"); board_set_status(STATUS_ERROR); Endpoint_StallTransaction(); return false; } return true; }
int8_t usbHandleBulk(uint8_t *request, uint8_t *status) { uint8_t cmd, proto; int8_t ret; uint16_t len; bool nibEarlyExit; // Clear off "just did reset" flag each time a different cmd is run. cmdSeqInProgress &= ~XUM1541_DOING_RESET; // Default is to return no data ret = XUM1541_IO_READY; cmd = request[0]; len = *(uint16_t *)&request[2]; board_set_status(STATUS_ACTIVE); switch (cmd) { case XUM1541_READ: // Disallow any other protocols if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT) == 0) proto = XUM_RW_PROTO(request[1]); else proto = XUM1541_CBM; DEBUGF(DBG_INFO, "rd:%d %d\n", proto, len); // loop to read all the bytes now, sending back each as we get it switch (proto) { case XUM1541_CBM: cmds->cbm_raw_read(len); ret = 0; break; case XUM1541_S1: ioReadLoop(s1_read_byte, len); ret = 0; break; case XUM1541_S2: ioReadLoop(s2_read_byte, len); ret = 0; break; case XUM1541_PP: ioRead2Loop(pp_read_2_bytes, len); ret = 0; break; case XUM1541_P2: ioReadLoop(p2_read_byte, len); ret = 0; break; case XUM1541_NIB: nibEarlyExit = (len & XUM1541_NIB_READ_VAR); len &= ~XUM1541_NIB_READ_VAR; ioReadNibLoop(len, nibEarlyExit); ret = 0; break; case XUM1541_NIB_COMMAND: ioReadLoop(nib_parburst_read_checked, len); ret = 0; break; #ifdef SRQ_NIB_SUPPORT case XUM1541_NIB_SRQ: ioReadNibSrqLoop(len); ret = 0; break; case XUM1541_NIB_SRQ_COMMAND: ioReadLoop(nib_srqburst_read_checked, len); ret = 0; break; #endif // SRQ_NIB_SUPPORT #ifdef TAPE_SUPPORT case XUM1541_TAP: XUM_SET_STATUS_VAL(status, Tape_Capture()); break; case XUM1541_TAP_CONFIG: XUM_SET_STATUS_VAL(status, Tape_DownloadConfig()); break; #endif // TAPE_SUPPORT default: DEBUGF(DBG_ERROR, "badproto %d\n", proto); ret = -1; } break; case XUM1541_WRITE: // Disallow any other protocols if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT) == 0) proto = XUM_RW_PROTO(request[1]); else proto = XUM1541_CBM; DEBUGF(DBG_INFO, "wr:%d %d\n", proto, len); // loop to fetch each byte and write it as we get it switch (proto) { case XUM1541_CBM: len = cmds->cbm_raw_write(len, XUM_RW_FLAGS(request[1])); XUM_SET_STATUS_VAL(status, len); break; case XUM1541_S1: ioWriteLoop(s1_write_byte, len); ret = 0; break; case XUM1541_S2: ioWriteLoop(s2_write_byte, len); ret = 0; break; case XUM1541_PP: ioWrite2Loop(pp_write_2_bytes, len); ret = 0; break; case XUM1541_P2: ioWriteLoop(p2_write_byte, len); ret = 0; break; case XUM1541_NIB: ioWriteNibLoop(len); ret = 0; break; case XUM1541_NIB_COMMAND: ioWriteLoop(nib_parburst_write_checked, len); ret = 0; break; #ifdef SRQ_NIB_SUPPORT case XUM1541_NIB_SRQ: ioWriteNibSrqLoop(len); ret = 0; break; case XUM1541_NIB_SRQ_COMMAND: ioWriteLoop(nib_srqburst_write_checked, len); ret = 0; break; #endif // SRQ_NIB_SUPPORT #ifdef TAPE_SUPPORT case XUM1541_TAP: XUM_SET_STATUS_VAL(status, Tape_Write()); break; case XUM1541_TAP_CONFIG: XUM_SET_STATUS_VAL(status, Tape_UploadConfig()); break; #endif // TAPE_SUPPORT default: DEBUGF(DBG_ERROR, "badproto %d\n", proto); ret = -1; } break; /* Low-level port access */ case XUM1541_GET_EOI: XUM_SET_STATUS_VAL(status, eoi ? 1 : 0); break; case XUM1541_CLEAR_EOI: eoi = 0; break; case XUM1541_IEC_WAIT: if (!cmds->cbm_wait(/*line*/request[1], /*state*/request[2])) { ret = 0; break; } /* FALLTHROUGH */ case XUM1541_IEC_POLL: XUM_SET_STATUS_VAL(status, cmds->cbm_poll()); DEBUGF(DBG_INFO, "poll=%x\n", XUM_GET_STATUS_VAL(status)); break; case XUM1541_IEC_SETRELEASE: cmds->cbm_setrelease(/*set*/request[1], /*release*/request[2]); break; case XUM1541_PP_READ: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } XUM_SET_STATUS_VAL(status, iec_pp_read()); break; case XUM1541_PP_WRITE: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } iec_pp_write(request[1]); break; case XUM1541_PARBURST_READ: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } XUM_SET_STATUS_VAL(status, nib_parburst_read_checked()); break; case XUM1541_PARBURST_WRITE: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } // Sets suppressNibCmd if we're doing a read/write track. nib_parburst_write_checked(request[1]); break; #ifdef SRQ_NIB_SUPPORT case XUM1541_SRQBURST_READ: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } XUM_SET_STATUS_VAL(status, nib_srqburst_read_checked()); break; case XUM1541_SRQBURST_WRITE: // Disallow if in IEEE mode. if ((currState & XUM1541_IEEE488_PRESENT)) { ret = -1; break; } // Sets suppressNibCmd if we're doing a read/write track. nib_srqburst_write_checked(request[1]); break; #endif // SRQ_NIB_SUPPORT #ifdef TAPE_SUPPORT case XUM1541_TAP_PREPARE_CAPTURE: XUM_SET_STATUS_VAL(status, Tape_PrepareCapture()); break; case XUM1541_TAP_PREPARE_WRITE: XUM_SET_STATUS_VAL(status, Tape_PrepareWrite()); break; case XUM1541_TAP_GET_SENSE: XUM_SET_STATUS_VAL(status, Tape_GetSense()); break; case XUM1541_TAP_WAIT_FOR_STOP_SENSE: XUM_SET_STATUS_VAL(status, Tape_WaitForStopSense()); break; case XUM1541_TAP_WAIT_FOR_PLAY_SENSE: XUM_SET_STATUS_VAL(status, Tape_WaitForPlaySense()); break; case XUM1541_TAP_MOTOR_ON: XUM_SET_STATUS_VAL(status, Tape_MotorOn()); break; case XUM1541_TAP_MOTOR_OFF: XUM_SET_STATUS_VAL(status, Tape_MotorOff()); break; case XUM1541_TAP_GET_VER: XUM_SET_STATUS_VAL(status, Tape_GetTapeFirmwareVersion()); break; #endif // TAPE_SUPPORT default: DEBUGF(DBG_ERROR, "ERR: bulk cmd %d not impl.\n", cmd); ret = -1; } return ret; }
/* * Process the given USB control command, storing the result in replyBuf * and returning the number of output bytes. Returns -1 if command is * invalid. All control processing has to happen until completion (no * delayed execution) and it may not take additional input from the host * (data direction set as host to device). * * The replyBuf is 8 bytes long. */ int8_t usbHandleControl(uint8_t cmd, uint8_t *replyBuf) { DEBUGF(DBG_INFO, "cmd %d (%d)\n", cmd, cmd - XUM1541_IOCTL); switch (cmd) { case XUM1541_ENTER_BOOTLOADER: enterBootLoader(); return 0; case XUM1541_ECHO: replyBuf[0] = cmd; return 1; case XUM1541_INIT: savedNibWritePtr = savedNibWrites; board_set_status(STATUS_ACTIVE); // First time: init IO pins and probe for IEC or IEEE devices if (cmds == NULL) cmds = cbm_init(); // If we still don't have a bus, something is really wrong. if (cmds == NULL) return -1; replyBuf[0] = XUM1541_VERSION; replyBuf[1] = XUM1541_CAPABILITIES; replyBuf[2] = currState; /* * Our previous transaction was interrupted in the middle, say by * the user pressing ^C. Reset the IEC bus and then enter the * stalled state. The host will clear the stall and continue * their new transaction. */ if (cmdSeqInProgress) { replyBuf[2] |= XUM1541_DOING_RESET; cmdSeqInProgress = XUM1541_DOING_RESET; cmds->cbm_reset(false); SetAbortState(); } cmdSeqInProgress |= XUM1541_CMD_IN_PROGRESS; /* * We wait in main() until at least one device is present on the * IEC bus. Notify the user if they requested a command before * that has been detected. */ if (!device_running) replyBuf[2] |= XUM1541_NO_DEVICE; return 8; case XUM1541_SHUTDOWN: cmdSeqInProgress = 0; board_set_status(STATUS_READY); return 0; case XUM1541_RESET: // Only do reset if we didn't just reset in INIT (above). if ((cmdSeqInProgress & XUM1541_DOING_RESET) == 0) cmds->cbm_reset(false); return 0; #ifdef TAPE_SUPPORT case XUM1541_TAP_BREAK: cmds->cbm_reset(false); return 0; #endif // TAPE_SUPPORT default: DEBUGF(DBG_ERROR, "ERR: control cmd %d not impl\n", cmd); return -1; } }