/* if yes, load thing token from memory */ uint8_t thethingsio_example_load_thing_token_nvm(void) { /* check for valid thing token in NVM of device */ uint8_t readBuffer_Temp[NVMCTRL_PAGE_SIZE] = { 0, }; uint8_t readToken_Temp[NVMCTRL_PAGE_SIZE] = { 0, }; enum status_code status = nvm_read_buffer(NVM_ADDR_THING_TOKEN, readBuffer_Temp, NVMCTRL_PAGE_SIZE); if(status != STATUS_OK) { printf("load thing token, read thing token error (0x%x)\r\n", status); return false; } // update thingsiO read write URL uint8_t thing_token_offset = sizeof(gau8TheThingsiOHttpRWUrl) - THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH - 1; memcpy((gau8TheThingsiOHttpRWUrl+thing_token_offset), readBuffer_Temp, THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH); // update thingIO subscribe URL // add by jb to support subscription uint8_t things_token_subscribe_offset = sizeof(gau0TheThingsIOHttpSubsURL) - THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH -1; memcpy((gau0TheThingsIOHttpSubsURL+things_token_subscribe_offset), readBuffer_Temp, THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH); printf("subscribe thing token %s", readBuffer_Temp); printf("URL subscription %s"DEBUG_EOL, gau0TheThingsIOHttpSubsURL); // memcpy((gau0TheThingsIOHttpSubsURL+things_token_subscribe_offset + sizeof(KEEP_ALIVE_VALUE)), KEEP_ALIVE_VALUE, sizeof(KEEP_ALIVE_VALUE)); return true; }
int main(void) { //! [setup_init] configure_nvm(); //! [setup_init] //! [main] //! [main_1] uint8_t page_buffer[NVMCTRL_PAGE_SIZE]; //! [main_1] //! [main_2] for (uint32_t i = 0; i < NVMCTRL_PAGE_SIZE; i++) { page_buffer[i] = i; } //! [main_2] //! [main_3] enum status_code error_code; //! [main_3] //! [main_4] do { error_code = nvm_erase_row( 100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE); } while (error_code == STATUS_BUSY); //! [main_4] //! [main_5] do { error_code = nvm_write_buffer( 100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE, page_buffer, NVMCTRL_PAGE_SIZE); } while (error_code == STATUS_BUSY); //! [main_5] //! [main_6] do { error_code = nvm_read_buffer( 100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE, page_buffer, NVMCTRL_PAGE_SIZE); } while (error_code == STATUS_BUSY); //! [main_6] //! [main] while (true) { /* Do nothing */ } }
static int samd21_flash_write(uint32_t address, const void *src, uint32_t len) { int base_address; int offset; struct nvm_parameters params; uint8_t page_buffer[64]; const uint8_t *psrc = src; /* make sure this fits into our stack buffer */ nvm_get_parameters(¶ms); assert(params.page_size <= sizeof(page_buffer)); /* get the page address (this is not a sector, there are 4 pages per * row */ while(len) { int write_len; base_address = address & ~(params.page_size - 1); offset = address - base_address; write_len = params.page_size - offset; if(write_len > len) { write_len = len; } if(nvm_read_buffer(base_address, page_buffer, params.page_size) != STATUS_OK) { return -1; } /* move the pointers since this is a sure thing */ len -= write_len; address += write_len; /* copy it into the page buffer */ while(write_len--) { page_buffer[offset++] = *psrc++; } /* 0x000054a4 */ #if 1 /* write back the page buffer buffer */ if(nvm_write_buffer(base_address,page_buffer, params.page_size) != STATUS_OK) { return -1; } #endif } return 0; }
/* check if thing has been configured already (thing token) */ uint8_t thethingsio_example_thing_token_available_nvm(void) { uint8_t token_saved = false; enum status_code status = nvm_read_buffer(NVM_ADDR_THING_TOKEN_SAVED, &token_saved, 1); if(status != STATUS_OK) { printf("load thing token, read NVM error (0x%x) \r\n", status); return false; } if(token_saved != true) { printf("load thing token, thing token does not exist in NVM \r\n"); return false; } return true; }
/** * \brief Test NVM update * * This test modifies first half of the test page with different pattern, * reads it back and checks whether the values are updated * * \param test Current test case. */ static void run_nvm_update_test(const struct test_case *test) { uint8_t buffer[NVMCTRL_PAGE_SIZE], i; enum status_code status; /* Skip test if NVM initialization failed */ test_assert_true(test, nvm_init_success == true, "NVM initialization failed, skipping test"); /* Fill half of the buffer with pattern 2 */ for (i = 0; i < (NVMCTRL_PAGE_SIZE / 2); i++) { buffer[i] = BYTE_PATTERN2(i); } /* Update first half of the test page with new data */ status = nvm_update_buffer(TEST_PAGE_ADDR, buffer, 0, (NVMCTRL_PAGE_SIZE / 2)); /* Validate whether the update operation is complete */ test_assert_true(test, status == STATUS_OK, "Update operation error"); /* Flush the buffer */ for (i = 0; i < NVMCTRL_PAGE_SIZE; i++) { buffer[i] = 0; } /* Read the NVM contents at test address to buffer */ status = nvm_read_buffer(TEST_PAGE_ADDR, buffer, NVMCTRL_PAGE_SIZE); /* Validate whether the read operation is complete */ test_assert_true(test, status == STATUS_OK, "Read operation error"); /* Check the integrity of data in NVM */ for (i = 0; i < (NVMCTRL_PAGE_SIZE / 2); i++) { test_assert_true(test, buffer[i] == BYTE_PATTERN2(i), "Value not expected @ byte %d (read: 0x%02x," " expected: 0x%02x)", i, buffer[i], BYTE_PATTERN2(i)); } for (i = (NVMCTRL_PAGE_SIZE / 2); i < NVMCTRL_PAGE_SIZE; i++) { test_assert_true(test, buffer[i] == BYTE_PATTERN1(i), "Value not expected @ byte %d (read: 0x%02x," " expected: 0x%02x)", i, buffer[i], BYTE_PATTERN1(i)); } }
static int samd21_flash_read(uint32_t address, void *dst, uint32_t num_bytes) { int base_address; int offset; struct nvm_parameters params; uint8_t page_buffer[64]; uint8_t *pdst = dst; /* make sure this fits into our stack buffer */ nvm_get_parameters(¶ms); assert(params.page_size <= sizeof(page_buffer)); /* get the page address (this is not a sector, there are 4 pages per * row */ while(num_bytes) { int read_len; base_address = address & ~(params.page_size - 1); offset = address - base_address; read_len = params.page_size - offset; if(read_len > num_bytes) { read_len = num_bytes; } if(nvm_read_buffer(base_address, page_buffer, params.page_size) != STATUS_OK) { return -1; } /* move the pointers since this is a sure thing now */ num_bytes -= read_len; address += read_len; /* copy it into the page buffer */ while(read_len--) { *pdst++ = page_buffer[offset++]; } } return 0; }
/** * \brief Updates an arbitrary section of a page with new data. * * Writes from a buffer to a given page in the NVM memory, retaining any * unmodified data already stored in the page. * * \note If manual write mode is enable, write command must be executed after * this function, otherwise the data will not write to NVM from page buffer. * * \warning This routine is unsafe if data integrity is critical; a system reset * during the update process will result in up to one row of data being * lost. If corruption must be avoided in all circumstances (including * power loss or system reset) this function should not be used. * * \param[in] destination_address Destination page address to write to * \param[in] buffer Pointer to buffer where the data to write is * stored * \param[in] offset Number of bytes to offset the data write in * the page * \param[in] length Number of bytes in the page to update * * \return Status of the attempt to update a page. * * \retval STATUS_OK Requested NVM memory page was successfully * read * \retval STATUS_BUSY NVM controller was busy when the operation * was attempted * \retval STATUS_ERR_BAD_ADDRESS The requested address was outside the * acceptable range of the NVM memory region * \retval STATUS_ERR_INVALID_ARG The supplied length and offset was invalid */ enum status_code nvm_update_buffer( const uint32_t destination_address, uint8_t *const buffer, uint16_t offset, uint16_t length) { enum status_code error_code = STATUS_OK; uint8_t row_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE]; /* Ensure the read does not overflow the page size */ if ((offset + length) > _nvm_dev.page_size) { return STATUS_ERR_INVALID_ARG; } /* Calculate the starting row address of the page to update */ uint32_t row_start_address = destination_address & ~((_nvm_dev.page_size * NVMCTRL_ROW_PAGES) - 1); /* Read in the current row contents */ for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) { do { error_code = nvm_read_buffer( row_start_address + (i * _nvm_dev.page_size), row_buffer[i], _nvm_dev.page_size); } while (error_code == STATUS_BUSY); if (error_code != STATUS_OK) { return error_code; } } /* Calculate the starting page in the row that is to be updated */ uint8_t page_in_row = (destination_address % (_nvm_dev.page_size * NVMCTRL_ROW_PAGES)) / _nvm_dev.page_size; /* Update the specified bytes in the page buffer */ for (uint32_t i = 0; i < length; i++) { row_buffer[page_in_row][offset + i] = buffer[i]; } system_interrupt_enter_critical_section(); /* Erase the row */ do { error_code = nvm_erase_row(row_start_address); } while (error_code == STATUS_BUSY); if (error_code != STATUS_OK) { system_interrupt_leave_critical_section(); return error_code; } /* Write the updated row contents to the erased row */ for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) { do { error_code = nvm_write_buffer( row_start_address + (i * _nvm_dev.page_size), row_buffer[i], _nvm_dev.page_size); } while (error_code == STATUS_BUSY); if (error_code != STATUS_OK) { system_interrupt_leave_critical_section(); return error_code; } } system_interrupt_leave_critical_section(); return error_code; }