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); } }
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(); } }
// 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; }
static void trigger_update(struct pru_data *pru) { prussdrv_pru_send_event(ARM_PRU0_INTERRUPT); }