// #################################################################################################
// # << NEORV32 - CRC Unit Demo Program >>                                                         #
// # ********************************************************************************************* #
// # BSD 3-Clause License                                                                          #
// #                                                                                               #
// # Copyright (c) 2023, Stephan Nolting. All rights reserved.                                     #
// #                                                                                               #
// # Redistribution and use in source and binary forms, with or without modification, are          #
// # permitted provided that the following conditions are met:                                     #
// #                                                                                               #
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
// #    conditions and the following disclaimer.                                                   #
// #                                                                                               #
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
// #    conditions and the following disclaimer in the documentation and/or other materials        #
// #    provided with the distribution.                                                            #
// #                                                                                               #
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
// #    endorse or promote products derived from this software without specific prior written      #
// #    permission.                                                                                #
// #                                                                                               #
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
// # ********************************************************************************************* #
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
// #################################################################################################


/**********************************************************************//**
 * @file demo_crc/main.c
 * @author Stephan Nolting
 * @brief CRC demo program.
 **************************************************************************/

#include <neorv32.h>


/**********************************************************************//**
 * @name User configuration
 **************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/**@}*/

// CRC test array
const uint8_t test_string[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00};


/**********************************************************************//**
 * Simple demo program to showcase the NEORV32 CRC unit.
 *
 * @note This program requires UART0 and the CRC unit to be synthesized.
 * The DMA controller is optional.
 *
 * @return Irrelevant.
 **************************************************************************/
int main() {

  // setup NEORV32 runtime environment
  neorv32_rte_setup();

  // setup UART at default baud rate, no interrupts
  neorv32_uart0_setup(BAUD_RATE, 0);

  // intro
  neorv32_uart0_printf("\n<<< CRC Unit Demo Program >>>\n\n");

  // check if CRC unit is implemented at all
  if (neorv32_crc_available() == 0) {
    neorv32_uart0_printf("ERROR! CRC unit not implemented!\n");
    return 1;
  }


  uint32_t result, polynomial, reference, seed;
  neorv32_uart0_printf("Test string: '%s'\n", test_string);

  // CRC8 example
  polynomial = 0x07;
  reference  = 0x5b; // generated by http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
  seed       = 0x00;
  neorv32_crc_setup(CRC_MODE8, polynomial, seed);
  result = neorv32_crc_block((uint8_t*)test_string, sizeof(test_string)) & 0xff;
  neorv32_uart0_printf("\n[CRC8]\n");
  neorv32_uart0_printf("Polynomial = 0x%x\n", polynomial);
  neorv32_uart0_printf("Seed       = 0x%x\n", seed);
  neorv32_uart0_printf("Result     = 0x%x ", result);
  if (result == reference) {
    neorv32_uart0_printf("[OK]\n");
  }
  else {
    neorv32_uart0_printf("[FAILED]\n");
  }

  // CRC16 example
  polynomial = 0x1021;
  reference  = 0x96B9; // generated by http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
  seed       = 0x0000;
  neorv32_crc_setup(CRC_MODE16, polynomial, seed);
  result = neorv32_crc_block((uint8_t*)test_string, sizeof(test_string)) & 0xffff;
  neorv32_uart0_printf("\n[CRC16]\n");
  neorv32_uart0_printf("Polynomial = 0x%x\n", polynomial);
  neorv32_uart0_printf("Seed       = 0x%x\n", seed);
  neorv32_uart0_printf("Result     = 0x%x ", result);
  if (result == reference) {
    neorv32_uart0_printf("[OK]\n");
  }
  else {
    neorv32_uart0_printf("[FAILED]\n");
  }

  // CRC32 example
  polynomial = 0x04C11DB7;
  reference  = 0xF58D7B78; // generated by http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
  seed       = 0xFFFFFFFF;
  neorv32_crc_setup(CRC_MODE32, polynomial, seed);
  result = neorv32_crc_block((uint8_t*)test_string, sizeof(test_string)) & 0xffffffff;
  neorv32_uart0_printf("\n[CRC32]\n");
  neorv32_uart0_printf("Polynomial = 0x%x\n", polynomial);
  neorv32_uart0_printf("Seed       = 0x%x\n", seed);
  neorv32_uart0_printf("Result     = 0x%x ", result);
  if (result == reference) {
    neorv32_uart0_printf("[OK]\n");
  }
  else {
    neorv32_uart0_printf("[FAILED]\n");
  }


  // CRC8 example using the DMA
  if (neorv32_dma_available() != 0) {

    uint32_t cmd;
    int rc;

    polynomial = 0x07;
    reference  = 0x5b; // generated by http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
    seed       = 0x00;
    neorv32_crc_setup(CRC_MODE8, polynomial, seed);

    neorv32_uart0_printf("\n[CRC8] using DMA\n");
    neorv32_uart0_printf("Polynomial = 0x%x\n", polynomial);
    neorv32_uart0_printf("Seed       = 0x%x\n", seed);

    neorv32_dma_enable();

    // configure transfer type
    cmd = DMA_CMD_B2UW     | // read source in byte quantities, write destination in WORD(!!) quantities
          DMA_CMD_SRC_INC  | // auto-increment source address
          DMA_CMD_DST_CONST; // constant destination address

    // configure automatic DMA transfer
    neorv32_dma_transfer((uint32_t)(&test_string[0]),    // source array base address (data = 0xff)
                         (uint32_t)(&NEORV32_CRC->DATA), // destination address = CRC data register (32-bit!)
                          sizeof(test_string),           // number of elements to transfer
                          cmd);                          // transfer type configuration

    // wait for transfer to complete using polling
    neorv32_uart0_printf("Waiting for DMA... ");
    while (1) {
      rc = neorv32_dma_status();
      if (rc == DMA_STATUS_IDLE) {
        neorv32_uart0_printf("Transfer done.\n");
        break;
      }
      else if ((rc == DMA_STATUS_ERR_RD) || (rc == DMA_STATUS_ERR_WR)) {
        neorv32_uart0_printf("Transfer failed!\n");
        break;
      }
    }

    // check DMA status
    rc = neorv32_dma_status();
    if ((rc == DMA_STATUS_ERR_RD) || (rc == DMA_STATUS_ERR_WR)) {
      neorv32_uart0_printf("Transfer failed!\n");
    }

    result = neorv32_crc_get() & 0xff;
    neorv32_uart0_printf("Result     = 0x%x ", result);
    if (result == reference) {
      neorv32_uart0_printf("[OK]\n");
    }
    else {
      neorv32_uart0_printf("[FAILED]\n");
    }

  }


  neorv32_uart0_printf("\nProgram completed.\n");
  return 0;
}
