Example #1
0
static void printImage(const uint32_t startLine, const uint32_t endLine,
        const bool inverse, const uint32_t paperFeedCountAfterPrint) {
    uint32_t y;

    // Initialize the printer queue and add the command to perform the low-level
    // initializations needed before we can start printing.
    initQueueJobItems();
    addJobItemToQueue(PRINTER_CMD_OPEN, 0, NULL);

    // Generate the print job and fill the printer queue line by line
    for (y = startLine; y < endLine; y++) {
        partitionLineAndPrint(pngImageRowPointers[y], pngImageWidth, inverse);
    }

    // See if a paper feed after printing was requested and add it to the queue
    if (paperFeedCountAfterPrint) {
        addJobItemToQueue(PRINTER_CMD_MOTOR_HALF_STEP, sizeof(uint32_t),
                (const uint8_t *)&paperFeedCountAfterPrint);
    }

    // Close out the print job properly including a shutdown of the PRU that
    // is no longer needed.
    addJobItemToQueue(PRINTER_CMD_CLOSE, 0, NULL);
    addJobItemToQueue(PRINTER_CMD_REQUEST_PRU_HALT, 0, NULL);
    addJobItemToQueue(PRINTER_CMD_EOS, 0, NULL);

    // See if there are still job items in the queue and print them if that's
    // the case (which is most likely).
    if (queueHasJobItems()) {
        // The interrupt is mapped via INTC to channel 1
        printf("Initiating section printing\n");
        prussdrv_pru_send_event(ARM_PRU1_INTERRUPT);

        // Wait until PRU1 has finished execution and acknowledge the interrupt.
        // The INTC config maps PRU1_ARM_INTERRUPT to EVTOUT_1.
        printf("Waiting for printer driver...\n");
        measureDurationPrintToConsole(true);
        prussdrv_pru_wait_event(PRU_EVTOUT_1);
        measureDurationPrintToConsole(false);
        prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);
    }
}
Example #2
0
static void addJobItemToQueue(const uint32_t command, const uint32_t length,
        const uint8_t data[]) {
    // Add the currently requested command to the queue. If this fails (and it
    // can in case the memory is full) then we print what's currently in the
    // queue, re-initialize the queue, and try again.
    while (!addJobItemToQueueLowLevel(command, length, data)) {
        // The interrupt is mapped via INTC to channel 1
        printf("Initiating section printing\n");
        prussdrv_pru_send_event(ARM_PRU1_INTERRUPT);

        // Wait until PRU1 has finished execution and acknowledge the interrupt.
        // The INTC config maps PRU1_ARM_INTERRUPT to EVTOUT_1.
        printf("Waiting for printer driver...\n");
        measureDurationPrintToConsole(true);
        prussdrv_pru_wait_event(PRU_EVTOUT_1);
        measureDurationPrintToConsole(false);
        prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);

        // Initialize printer job item queue to be ready to be filled again
        initQueueJobItems();
    }
}
Example #3
0
// Main Linux program entry point
int main(int argc, char *argv[]) {
    int opt;
    bool testFlag = false;
    bool paperFeedFlag = false;
    uint32_t paperFeedCount = 0;
    bool startLineFlag = false;
    uint32_t startLine = 0;
    bool endLineFlag = false;
    uint32_t endLine = 0;
    bool inverseFlag = false;
    bool waitFlag = false;

    // Parse the command line options and issue a simple help text in case
    // things don't match up. The columns behind the options denote that option
    // requires an argument. See getopt(3) for more info.
    while ((opt = getopt(argc, argv, "tf:s:e:iw")) != -1) {
        switch (opt) {
        case 't':
            testFlag = true;
            break;
        case 'f':
            paperFeedCount = atoi(optarg);
            paperFeedFlag = true;
            break;
        case 's':
            startLine = atoi(optarg);
            startLineFlag = true;
            break;
        case 'e':
            endLine = atoi(optarg);
            endLineFlag = true;
            break;
        case 'i':
            inverseFlag = true;
            break;
        case 'w':
            waitFlag = true;
            break;
        default:
            // getopt() will return '?' in case of a malformed command line in
            // which case we are printing the usage and exit the command.
            fprintf(stderr, USAGE_STRING, argv[0], argv[0], argv[0]);
            return EXIT_FAILURE;
        }
    }

    // Initialize the PRU and exit the program if that fails. Any errors that
    // may occur during that process will be output from within that function.
    if (!initPru()) {
        return EXIT_FAILURE;
    }

    // See if the test mode has been activated. If that's the case we will just
    // enter test mode right away.
    if (testFlag) {
        // Create a very simple print job that activates the test pattern
        // generation. Since this sub-function doesn't return within the PRU
        // firmware we don't need to bother trying to issue a halt command.
        initQueueJobItems();
        addJobItemToQueue(PRINTER_CMD_TEST_SIGNALS, 0, NULL);
        addJobItemToQueue(PRINTER_CMD_EOS, 0, NULL);

        // The interrupt is mapped via INTC to channel 1
        printf("Starting PRU GPIO test pattern generation\n");
        prussdrv_pru_send_event(ARM_PRU1_INTERRUPT);
    }
    // See if the paper feed flag has been set AND no image filename was given.
    // Unlike other print-related flags we want to allow the user to feed paper
    // without needing to specify an image to print.
    else if (paperFeedFlag && (optind >= argc)) {
        // Go ahead and create a very simple print job that simply feeds the
        // paper by the specified number of steps. Any other print-related
        // command line option will be ignored.
        initQueueJobItems();
        addJobItemToQueue(PRINTER_CMD_OPEN, 0, NULL);
        addJobItemToQueue(PRINTER_CMD_MOTOR_HALF_STEP, sizeof(uint32_t),
                (const uint8_t *)&paperFeedCount);
        addJobItemToQueue(PRINTER_CMD_CLOSE, 0, NULL);
        addJobItemToQueue(PRINTER_CMD_REQUEST_PRU_HALT, 0, NULL);
        addJobItemToQueue(PRINTER_CMD_EOS, 0, NULL);

        // The interrupt is mapped via INTC to channel 1
        printf("Start feeding paper\n");
        prussdrv_pru_send_event(ARM_PRU1_INTERRUPT);

        // Wait until PRU1 has finished execution and acknowledge the interrupt.
        // The INTC config maps PRU1_ARM_INTERRUPT to EVTOUT_1.
        printf("Waiting for paper feed completion...\n");
        measureDurationPrintToConsole(true);
        prussdrv_pru_wait_event(PRU_EVTOUT_1);
        measureDurationPrintToConsole(false);
        prussdrv_pru_clear_event(PRU_EVTOUT_1, PRU1_ARM_INTERRUPT);

        // See if any errors occurred and output them to the console if any
        checkForPrinterErrorsPrintToConsole();
    }
    // See if we are in the normal printer operating mode which means the user
    // has provided an image filename parameter.
    else if (optind < argc) {
        // Let's go ahead and print the image considering any of the other
        // command line flags that may have been set.
        const char *imageFile = argv[optind];

        printf("Loading image %s\n", imageFile);
        if (!readPngImage(imageFile)) {
            return EXIT_FAILURE;
        }

        // Check if a start line was given and use it if it is a valid
        // parameter. Otherwise use the first line of the image.
        if (startLineFlag) {
            if ((startLine < 0) || (startLine >= pngImageHeight)) {
                fprintf(stderr, "Invalid start line!\n");
                return EXIT_FAILURE;
            }
        }
        else {
            startLine = 0;
        }

        // Check if an end line was given and use it if it is a valid
        // parameter. Otherwise use the last line of the image.
        if (endLineFlag) {
            if ((endLine < 0) || (endLine >= pngImageHeight)) {
                fprintf(stderr, "Invalid end line!\n");
                return EXIT_FAILURE;
            }
        }
        else {
            endLine = pngImageHeight - 1;
        }

        // Make sure the parameters actually make sense
        if (startLine > endLine) {
            fprintf(stderr, "The start line must not be larger than the end" \
                    " line!\n");
            return EXIT_FAILURE;
        }

        // Check the width of the image. If it's too wide we'll continue with
        // printing anyways. We just won't output the full line.
        if (pngImageWidth > PRINTER_DOTS_PER_LINE) {
            printf("Image width exceeds the maximum number of dots allowed" \
                    " per line! Will only be printing the first %u pixels...",
                    PRINTER_DOTS_PER_LINE);
        }

        printf("Processing image, transferring into PRU shared memory, and " \
                "starting print job\n");
        printImage(startLine, endLine, inverseFlag, paperFeedCount);

        // Free the PNG image from memory. It's no longer needed-- all relevant
        // data was transferred into the PRU shared memory.
        deallocPngImage();

        // See if any errors occurred and output them to the console if any
        checkForPrinterErrorsPrintToConsole();
    }
    // Looks like no command line parameters or an invalid combination thereof
    // was encountered...
    else {
        // Print the usage info to the console and exit with error
        fprintf(stderr, USAGE_STRING, argv[0], argv[0], argv[0]);
        return EXIT_FAILURE;
    }

    if (waitFlag) {
        printf("Press ENTER to disable the PRU and end the program...\n");
        getchar();
    }

    disablePru();

    return EXIT_SUCCESS;
}
Example #4
0
static void trigger_update(struct pru_data *pru)
{
	prussdrv_pru_send_event(ARM_PRU0_INTERRUPT);
}