Example #1
0
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;
}
Example #3
0
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();
    }
}
Example #4
0
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);
}
Example #5
0
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();
    }
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
/*
 * 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;
    }
}