/****************************************************************************** * * Copyright(c) 2007 - 2015 Realtek Corporation. All rights reserved. * * ******************************************************************************/ #include #if CONFIG_EXAMPLE_SPI_ATCMD #include "FreeRTOS.h" #include "task.h" #include #include "semphr.h" #include "device.h" #include "osdep_api.h" #include "osdep_service.h" #include "device_lock.h" #include "spi_atcmd/example_spi_atcmd.h" #include "at_cmd/log_service.h" #include "at_cmd/atcmd_wifi.h" #include "at_cmd/atcmd_lwip.h" #include "flash_api.h" #include "spi_api.h" #include "spi_ex_api.h" #include "gpio_irq_api.h" #include "gpio_irq_ex_api.h" /**** SPI FUNCTIONS ****/ spi_t spi_obj; gpio_t gpio_cs; #define SPI_RX_BUFFER_SIZE ATSTRING_LEN/2 #define SPI_TX_BUFFER_SIZE ATSTRING_LEN/2 uint16_t spi_chunk_buffer[ATSTRING_LEN/2]; _Sema master_rx_done_sema; _Sema master_tx_done_sema; #define SPI_USE_STREAM (0) #define SPI_USE_DMA (1) /**** SLAVE HARDWARE READY ****/ gpio_t gpio_hrdy; #define SPI_SLAVE_BUSY 0 #define SPI_SLAVE_READY 1 volatile int spi_slave_status = SPI_SLAVE_BUSY; _Sema spi_check_hrdy_sema; #define BLOCKING 1 #define NONBLOCKING 0 volatile int hrdy_pull_down_counter = 0; /**** SLAVE SYNC ****/ gpio_irq_t gpio_sync; #define SPI_STATE_MISO 0 #define SPI_STATE_MOSI 1 int spi_state = SPI_STATE_MISO; /**** TASK THREAD ****/ _Sema spi_check_trx_sema; /**** LOG SERVICE ****/ char at_string[ATSTRING_LEN]; extern char log_buf[LOG_SERVICE_BUFLEN]; extern xSemaphoreHandle log_rx_interrupt_sema; #define LOG_TX_BUFFER_SIZE 48*1024 char log_tx_buffer[LOG_TX_BUFFER_SIZE]; uint32_t log_tx_idx = 0; uint32_t log_rx_idx = 0; /**** DATA FORMAT ****/ #define PREAMBLE_COMMAND 0x6000 #define PREAMBLE_DATA_READ 0x1000 #define PREAMBLE_DATA_WRITE 0x0000 #define COMMAND_DUMMY 0x0000 #define COMMAND_BEGIN 0x0304 #define COMMAND_END 0x0305 #define COMMAND_READ_BEGIN 0x0012 #define COMMAND_READ_RAW 0x0013 #define COMMAND_WRITE_BEGIN 0x0014 #define COMMAND_READ_WRITE_END 0x0015 #define REGISTER_ADDR 0x2000 void atcmd_update_partition_info(AT_PARTITION id, AT_PARTITION_OP ops, u8 *data, u16 len) { flash_t flash; int size, offset, i; u32 read_data; switch(id){ case AT_PARTITION_SPI: size = SPI_CONF_DATA_SIZE; offset = SPI_CONF_DATA_OFFSET; break; case AT_PARTITION_WIFI: size = WIFI_CONF_DATA_SIZE; offset = WIFI_CONF_DATA_OFFSET; break; case AT_PARTITION_LWIP: size = LWIP_CONF_DATA_SIZE; offset = LWIP_CONF_DATA_OFFSET; break; case AT_PARTITION_ALL: size = 0x1000; offset = 0; break; default: printf("partition id is invalid!\r\n"); return; } device_mutex_lock(RT_DEV_LOCK_FLASH); if(id == AT_PARTITION_ALL && ops == AT_PARTITION_ERASE){ flash_erase_sector(&flash, SPI_SETTING_SECTOR); goto exit; } if(ops == AT_PARTITION_READ){ flash_stream_read(&flash, SPI_SETTING_SECTOR+offset, len, data); goto exit; } //erase BACKUP_SECTOR flash_erase_sector(&flash, SPI_SETTING_BACKUP_SECTOR); if(ops == AT_PARTITION_WRITE){ // backup new data flash_stream_write(&flash, SPI_SETTING_BACKUP_SECTOR+offset, len, data); } //backup front data to backup sector for(i = 0; i < offset; i += sizeof(read_data)){ flash_read_word(&flash, SPI_SETTING_SECTOR + i, &read_data); flash_write_word(&flash, SPI_SETTING_BACKUP_SECTOR + i,read_data); } //backup rear data for(i = (offset + size); i < 0x1000; i += sizeof(read_data)){ flash_read_word(&flash, SPI_SETTING_SECTOR + i, &read_data); flash_write_word(&flash, SPI_SETTING_BACKUP_SECTOR + i,read_data); } //erase UART_SETTING_SECTOR flash_erase_sector(&flash, SPI_SETTING_SECTOR); //retore data to UART_SETTING_SECTOR from UART_SETTING_BACKUP_SECTOR for(i = 0; i < 0x1000; i+= sizeof(read_data)){ flash_read_word(&flash, SPI_SETTING_BACKUP_SECTOR + i, &read_data); flash_write_word(&flash, SPI_SETTING_SECTOR + i,read_data); } //erase BACKUP_SECTOR flash_erase_sector(&flash, SPI_SETTING_BACKUP_SECTOR); exit: device_mutex_unlock(RT_DEV_LOCK_FLASH); return; } /* AT cmd V2 API */ void spi_at_send_string(char *str) { spi_at_send_buf(str, strlen(str)); } /* AT cmd V2 API */ void spi_at_send_buf(u8 *buf, u32 len) { int i; int spi_tx_tail_next; if( !len || (!buf) ){ return; } if (buf == log_tx_buffer) { log_tx_idx = len; } else { for (i=0; i 4) { if (strncmp(buf, "ATPT", 4) == 0) { for (i=0; i 0) { /* Slave hw is ready, and Master has something to send. */ // stage A, read target address txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_BEGIN; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); gpio_write(&gpio_cs, 0); spi_chunk_buffer[0] = PREAMBLE_DATA_READ; spi_master_send(&spi_obj, spi_chunk_buffer, 1 * 2); spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); dummy = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); L_address = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); H_address = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); L_size = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); H_size = spi_chunk_buffer[0]; gpio_write(&gpio_cs, 1); // stage B, write data txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_WRITE_BEGIN; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); if (log_tx_idx % 2 != 0) { log_tx_buffer[log_tx_idx++] = 0; } send_len = log_tx_idx / 2; L_size = send_len & 0x0000FFFF; H_size = (send_len & 0xFFFF0000) >> 16; gpio_write(&gpio_cs, 0); txlen = 1; spi_chunk_buffer[0] = PREAMBLE_DATA_WRITE; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = L_address; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = H_address; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = L_size; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = H_size; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); gpio_write(&gpio_cs, 0); txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_WRITE; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); txlen = log_tx_idx/2; spi_master_send(&spi_obj, log_tx_buffer, txlen * 2); // sending raw data gpio_write(&gpio_cs, 1); // stage C, write data end txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_READ_WRITE_END; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); // stage final txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_END; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); L_size = log_tx_idx & 0x0000FFFF; H_size = (log_tx_idx & 0xFFFF0000) >> 16; txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_WRITE; spi_chunk_buffer[txlen++] = L_size; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_WRITE; spi_chunk_buffer[txlen++] = H_size; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); // finalize log_tx_idx = 0; } } else if (spi_state == SPI_STATE_MISO) { /* Slave hw is ready, and Slave want to send something. */ do { // stage A, read target address txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_BEGIN; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_READ; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); dummy = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); L_address = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); H_address = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); L_size = spi_chunk_buffer[0]; spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); H_size = spi_chunk_buffer[0]; gpio_write(&gpio_cs, 1); recv_len = ((H_size << 16) | L_size); if (recv_len == 0) { break; } // Stage B, confirm addr & len txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_READ_BEGIN; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); gpio_write(&gpio_cs, 0); txlen = 1; spi_chunk_buffer[0] = PREAMBLE_DATA_WRITE; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = L_address; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = H_address; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = L_size; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_chunk_buffer[0] = H_size; spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); // Stage C, begin to read txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_READ_RAW; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_READ; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); spi_master_recv(&spi_obj, spi_chunk_buffer, 1 * 2); // recv dummy rxlen = recv_len; spi_master_recv(&spi_obj, log_buf, rxlen * 2); log_buf[rxlen*2]= '\0'; gpio_write(&gpio_cs, 1); // Stage D, read end txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_READ_WRITE_END; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); // stage final txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_COMMAND; spi_chunk_buffer[txlen++] = COMMAND_END; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); L_size = (recv_len) & 0x0000FFFF; H_size = ((recv_len) & 0xFFFF0000) >> 16; txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_WRITE; spi_chunk_buffer[txlen++] = L_size; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); txlen = 0; spi_chunk_buffer[txlen++] = PREAMBLE_DATA_WRITE; spi_chunk_buffer[txlen++] = H_size; gpio_write(&gpio_cs, 0); spi_master_send(&spi_obj, spi_chunk_buffer, txlen * 2); gpio_write(&gpio_cs, 1); // finalize //printf("%s", log_buf); atcmd_check_special_case(log_buf); RtlUpSema(&log_rx_interrupt_sema); taskYIELD(); } while (0); } } vTaskDelete(NULL); } static void spi_atcmd_thread(void *param) { p_wlan_init_done_callback = NULL; atcmd_wifi_restore_from_flash(); atcmd_lwip_restore_from_flash(); rtw_msleep_os(20); spi_atcmd_main(); // the rx_buffer of atcmd is to receive and sending out to log_tx atcmd_lwip_set_rx_buffer(log_tx_buffer, sizeof(log_tx_buffer)); at_set_debug_mask(0x0); if(xTaskCreate(spi_trx_thread, ((const char*)"spi_trx_thread"), 4096, NULL, tskIDLE_PRIORITY+1 , NULL) != pdPASS) printf("\n\r%s xTaskCreate(spi_trx_thread) failed", __FUNCTION__); vTaskDelete(NULL); } int spi_atcmd_module_init(void){ if(xTaskCreate(spi_atcmd_thread, ((const char*)"spi_atcmd_thread"), 1024, NULL, tskIDLE_PRIORITY+1 , NULL) != pdPASS) printf("\n\r%s xTaskCreate(spi_atcmd_thread) failed", __FUNCTION__); return 0; } void example_spi_atcmd(void) { p_wlan_init_done_callback = spi_atcmd_module_init; return; } #endif // #if CONFIG_EXAMPLE_SPI_ATCMD