/** \brief method to change the bus speed of I2C * \param[in] interface on which to change bus speed * \param[in] baud rate (typically 100000 or 400000) */ void change_i2c_speed( ATCAIface iface, uint32_t speed ) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; switch(bus) { case 0: //pmc_enable_periph_clk(ID_TWI0); //flexcom_enable(FLEXCOM0); //flexcom_set_opmode(FLEXCOM0, FLEXCOM_TWI); flexcom_enable(FLEX_Channel0); flexcom_set_opmode(FLEX_Channel0, FLEXCOM_TWI); opt_twi_master.master_clk = sysclk_get_cpu_hz(); opt_twi_master.speed = speed; opt_twi_master.smbus = 0; //twi_master_init(TWI0, &opt_twi_master); twi_master_init(TWI_Channel0, &opt_twi_master); break; case 1: //pmc_enable_periph_clk(ID_TWI1); flexcom_enable(FLEX_Channel1); flexcom_set_opmode(FLEX_Channel1, FLEXCOM_TWI); opt_twi_master.master_clk = sysclk_get_cpu_hz(); opt_twi_master.speed = speed; opt_twi_master.smbus = 0; twi_master_init(TWI_Channel1, &opt_twi_master); break; } }
ATCA_STATUS hal_swi_wake(ATCAIface iface) { #ifdef DEBUG_HAL printf("hal_swi_wake()\r\n"); #endif ATCA_STATUS status = ATCA_COMM_FAIL; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcaswi.bus; int retries = cfg->rx_retries; uint16_t datalength = 4; uint8_t data[4] = { 0x00, 0x00, 0x00, 0x00 }, expected[4] = { 0x04, 0x11, 0x33, 0x43 }; while ((status != ATCA_SUCCESS) && (retries >= 0x00)) { retries--; // Change baudrate to 115200 to get low signal more than 60us swi_uart_setbaud(swi_hal_data[bus], 115200); // Send byte 0x00 status = swi_uart_send_byte(swi_hal_data[bus], SWI_WAKE_TOKEN); // Change baudrate back to 230400 swi_uart_setbaud(swi_hal_data[bus], 230400); } if (!status) { atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure status = hal_swi_receive(iface, data, &datalength); } if ((retries == 0x00) && (status != ATCA_SUCCESS) ) return ATCA_TIMEOUT; if ( memcmp( data, expected, 4 ) == 0 ) return ATCA_SUCCESS; return ATCA_COMM_FAIL; }
/** * \brief wake up CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to wakeup * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint32_t bdrt = cfg->atcai2c.baud; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; if ( bdrt != 100000 ) // if not already at 100KHz, change it change_i2c_speed(iface, 100000); // Send 0x00 as wake pulse i2c_write(i2c_hal_data[bus]->id, 0x00, NULL, NULL); atca_delay_ms(3); // wait tWHI + tWLO which is configured based on device type and configuration structure //atca_delay_us(cfg->wake_delay); // if necessary, revert baud rate to what came in. if ( bdrt != 100000 ) change_i2c_speed(iface, cfg->atcai2c.baud); i2c_read(i2c_hal_data[bus]->id, cfg->atcai2c.slave_address, data, 4); if (memcmp(data, expected, 4) == 0) return ATCA_SUCCESS; return ATCA_COMM_FAIL; }
/** \brief HAL implementation of kit protocol send over USB CDC * \param[in] ATCAIface instance * \param[out] rxdata pointer to space to receive the data * \param[inout] ptr to expected number of receive bytes to request * \return ATCA_STATUS */ ATCA_STATUS kit_phy_receive(ATCAIface iface, uint8_t* rxdata, int* rxsize) { ATCA_STATUS status = ATCA_SUCCESS; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int cdcid = cfg->atcauart.port; atcacdc_t* pCdc = (atcacdc_t*)atgetifacehaldat(iface); uint8_t buffer[CDC_BUFFER_MAX] = { 0 }; bool continue_read = true; int bytes_read = 0; uint16_t total_bytes = 0; char* location = NULL; int bytes_remain = 0; int bytes_to_cpy = 0; do { // Verify the input variables if ((rxdata == NULL) || (rxsize == NULL) || (pCdc == NULL)) { status = ATCA_BAD_PARAM; break; } // Verify the write handle if (pCdc->kits[cdcid].read_handle == INVALID_HANDLE_VALUE) { status = ATCA_COMM_FAIL; break; } // Read all of the bytes while (continue_read == true) { bytes_read = read(pCdc->kits[cdcid].read_handle, buffer, CDC_BUFFER_MAX); // Find the location of the '\n' character in read buffer // todo: generalize this read... it only applies if there is an ascii protocol with an <eom> of \n and if the <eom> exists location = strchr((char*)&buffer[0], '\n'); if (location == NULL) // Copy all of the bytes bytes_to_cpy = bytes_read; else{ // Copy only the bytes remaining in the read buffer to the <eom> bytes_to_cpy = (uint8_t)(location - (char*)buffer) + 1; // The response has been received, stop receiving more data continue_read = false; } // Protect rxdata from overwriting, this will have the result of truncating the returned bytes // Remaining space in rxdata bytes_remain = (*rxsize - total_bytes); // Use the minimum between number of bytes read and remaining space bytes_to_cpy = min(bytes_remain, bytes_to_cpy); // Copy the received data memcpy(&rxdata[total_bytes], &buffer[0], bytes_to_cpy); total_bytes += bytes_to_cpy; } } while (0); *rxsize = total_bytes; #ifdef KIT_DEBUG printf("<-- %s", rxdata ); #endif return status; }
/** * \brief HAL implementation of I2C receive function for ASF I2C * * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[in] rxlength ptr to expected number of receive bytes to request * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; i2c_read(i2c_hal_data[bus]->id, cfg->atcai2c.slave_address, rxdata, *rxlength); return ATCA_SUCCESS; }
/** \brief HAL implementation of I2C receive function for ASF I2C * \param[in] ATCAIface instance * \param[in] rxdata pointer to space to receive the data * \param[in] ptr to expected number of receive bytes to request * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { #ifdef DEBUG_HAL printf("hal_i2c_receive()\r\n"); #endif ATCAIfaceCfg *cfg = atgetifacecfg(iface); int retries = cfg->rx_retries; int bus = cfg->atcai2c.bus; uint32_t status = !TWI_SUCCESS; //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)rxdata, .length = (uint32_t)*rxlength }; switch(bus) { case 0: while(retries-- > 0 && status != TWI_SUCCESS) { //status = twi_master_read(TWI0, &packet); status = twi_master_read(TWI_Channel0, &packet); } break; case 1: while(retries-- > 0 && status != TWI_SUCCESS) { status = twi_master_read(TWI_Channel1, &packet); } break; } if (status != TWI_SUCCESS) { return ATCA_COMM_FAIL; } #ifdef DEBUG_HAL printf("\r\nResponse Packet (size:0x%.4x)\r\n", rxlength); printf("Count : %.2x\r\n", rxdata[0]); if (rxdata[0] > 3) { printf("Data : "); print_array(&rxdata[1], rxdata[0]-3); printf("CRC : "); print_array(&rxdata[rxdata[0]-2], 2); } printf("\r\n"); #endif return ATCA_SUCCESS; }
/** * \brief sleep CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to sleep * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x01; // idle word address value i2c_write(i2c_hal_data[bus]->id, cfg->atcai2c.slave_address, data, 1); return ATCA_SUCCESS; }
/** * \brief HAL implementation of I2C send over ASF * * \param[in] iface instance * \param[in] txdata pointer to space to bytes to send * \param[in] txlength number of bytes to send * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; txdata[0] = 0x03; // insert the Word Address Value, Command token txlength++; // account for word address value byte. i2c_write(i2c_hal_data[bus]->id, cfg->atcai2c.slave_address, txdata, txlength); return ATCA_SUCCESS; }
/** * \brief method to change the bus speed of I2C * * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ void change_i2c_speed(ATCAIface iface, uint32_t speed) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; // Disable the I2C bus I2CEnable(i2c_hal_data[bus]->id, FALSE); // Set the I2C baudrate I2CSetFrequency(i2c_hal_data[bus]->id, GetPeripheralClock(), speed); // Enable the I2C bus I2CEnable(i2c_hal_data[bus]->id, TRUE); }
/** * \brief method to change the bus speed of I2C * * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ void change_i2c_speed(ATCAIface iface, uint32_t speed) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; pmc_enable_periph_clk(i2c_hal_data[bus]->twi_id); opt_twi_master.master_clk = sysclk_get_cpu_hz(); opt_twi_master.speed = speed; opt_twi_master.smbus = 0; twi_master_init(i2c_hal_data[bus]->twi_master_instance, &opt_twi_master); }
/** * \brief HAL implementation of I2C send over ASF * * \param[in] iface instance * \param[in] txdata pointer to space to bytes to send * \param[in] txlength number of bytes to send * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { #ifdef DEBUG_HAL printf("hal_i2c_send()\r\n"); printf("\r\nCommand Packet (size:0x%.8x)\r\n", (uint32_t)txlength); printf("Count : %.2x\r\n", txdata[1]); printf("Opcode : %.2x\r\n", txdata[2]); printf("Param1 : %.2x\r\n", txdata[3]); printf("Param2 : "); print_array(&txdata[4], 2); if (txdata[1] > 7) { printf("Data : "); print_array(&txdata[6], txdata[1] - 7); } printf("CRC : "); print_array(&txdata[txdata[1] - 1], 2); printf("\r\n"); #endif ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; txdata[0] = 0x03; // insert the Word Address Value, Command token txlength++; // account for word address value byte. twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)txdata, .length = (uint32_t)txlength //(uint32_t)txdata[1] }; // for this implementation of I2C with CryptoAuth chips, txdata is assumed to have ATCAPacket format // other device types that don't require i/o tokens on the front end of a command need a different hal_i2c_send and wire it up instead of this one // this covers devices such as ATSHA204A and ATECCx08A that require a word address value pre-pended to the packet if (twi_master_write(i2c_hal_data[bus]->twi_master_instance, &packet) != TWI_SUCCESS) return ATCA_COMM_FAIL; return ATCA_SUCCESS; }
ATCA_STATUS hal_swi_send_flag(ATCAIface iface, uint8_t data) { ATCA_STATUS status = ATCA_SUCCESS; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcaswi.bus; uint8_t bit_mask, bit_data; for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { // Send one byte that represent one bit, 0x7F for one or 0x7D for zero // The LSB (least significant bit) is sent first. bit_data = (bit_mask & data) ? 0x7F : 0x7D; status |= swi_uart_send_byte(swi_hal_data[bus], bit_data); } if (status != ATCA_SUCCESS) return ATCA_COMM_FAIL; else return ATCA_SUCCESS; }
ATCA_STATUS hal_swi_send(ATCAIface iface, uint8_t *txdata, int txlength) { #ifdef DEBUG_HAL printf("hal_swi_send()\r\n"); printf("\r\nCommand Packet (size:0x%.4x)\r\n", txlength); printf("Count : %.2x\r\n", txdata[1]); printf("Opcode : %.2x\r\n", txdata[2]); printf("Param1 : %.2x\r\n", txdata[3]); printf("Param2 : "); print_array(&txdata[4], 2); if (txdata[1] > 7) { printf("Data : "); print_array(&txdata[6], txdata[1] - 7); } printf("CRC : "); print_array(&txdata[txdata[1] - 1], 2); printf("\r\n"); #endif ATCA_STATUS status = ATCA_SUCCESS; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcaswi.bus; uint8_t i, bit_mask, bit_data; //Skip the Word Address data as SWI doesn't use it txdata++; status = hal_swi_send_flag(iface, SWI_FLAG_CMD); if (status == ATCA_SUCCESS) { for (i = 0; i < txlength; i++) { for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { // Send one byte that represent one bit, 0x7F for one or 0x7D for zero // The LSB (least significant bit) is sent first. bit_data = (bit_mask & *txdata) ? 0x7F : 0x7D; status = swi_uart_send_byte(swi_hal_data[bus], bit_data); if (status != ATCA_SUCCESS) return ATCA_COMM_FAIL; } txdata++; } return ATCA_SUCCESS; } return ATCA_COMM_FAIL; }
/** \brief HAL implementation of Kit USB CDC post init * \param[in] ATCAIface instance * \return ATCA_STATUS */ ATCA_STATUS hal_kit_cdc_post_init(ATCAIface iface) { ATCA_STATUS status = ATCA_SUCCESS; atcacdc_t* phaldat = atgetifacehaldat(iface); ATCAIfaceCfg *cfg = atgetifacecfg(iface); int cdcid = cfg->atcauart.port; int i = 0; // Init all kit USB devices for (i = 0; i < phaldat->num_kits_found; i++) { // Set the port cfg->atcauart.port = i; // Perform the kit protocol init status = kit_init(iface); if (status != ATCA_SUCCESS) return status; } return status; }
/** * \brief HAL implementation of I2C receive function for ASF I2C * * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[in] rxlength ptr to expected number of receive bytes to request * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { #ifdef DEBUG_HAL printf("hal_i2c_receive()\r\n"); #endif ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t status = !TWI_SUCCESS; twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)rxdata, .length = (uint32_t)*rxlength }; while (retries-- > 0 && status != TWI_SUCCESS) status = twi_master_read(i2c_hal_data[bus]->twi_master_instance, &packet); if (status != TWI_SUCCESS) return ATCA_COMM_FAIL; #ifdef DEBUG_HAL printf("\r\nResponse Packet (size:0x%.4x)\r\n", rxlength); printf("Count : %.2x\r\n", rxdata[0]); if (rxdata[0] > 3) { printf("Data : "); print_array(&rxdata[1], rxdata[0] - 3); printf("CRC : "); print_array(&rxdata[rxdata[0] - 2], 2); } printf("\r\n"); #endif return ATCA_SUCCESS; }
/** \brief HAL implementation of send over USB CDC * \param[in] ATCAIface instance * \param[in] txdata pointer to bytes to send * \param[in] txlength number of bytes to send * \return ATCA_STATUS */ ATCA_STATUS kit_phy_send(ATCAIface iface, uint8_t* txdata, int txlength) { ATCA_STATUS status = ATCA_SUCCESS; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int cdcid = cfg->atcauart.port; atcacdc_t* pCdc = (atcacdc_t*)atgetifacehaldat(iface); size_t bytesWritten = 0; #ifdef KIT_DEBUG printf("--> %s", txdata ); #endif // Verify the input parameters if ((txdata == NULL) || (pCdc == NULL)) return ATCA_BAD_PARAM; // Verify the write handle if (pCdc->kits[cdcid].write_handle == INVALID_HANDLE_VALUE) return ATCA_COMM_FAIL; // Write the bytes to the specified com port bytesWritten = write(pCdc->kits[cdcid].write_handle, txdata, txlength); return status; }
/** \brief wake up CryptoAuth device using I2C bus * \param[in] interface to logical device to wakeup */ ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t bdrt = cfg->atcai2c.baud; uint8_t data[4], expected[4] = { 0x04,0x11,0x33,0x43 }; int status = !TWI_SUCCESS; // if not already at 100KHz, change it if (bdrt != 100000) { change_i2c_speed(iface, 100000); } // Send 0x00 as wake pulse switch(bus) { //case 0: twi_write_byte(TWI0, 0x00); break; case 0: twi_write_byte(TWI_Channel0,0);break; case 1: twi_write_byte(TWI_Channel1,0); break; } atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 4 }; // if necessary, revert baud rate to what came in. if (bdrt != 100000) { change_i2c_speed(iface, bdrt); } switch(bus) { case 0: //if (twi_master_read(TWI0, &packet) != TWI_SUCCESS) while (retries-- > 0 && status != TWI_SUCCESS) status = twi_master_read(TWI_Channel0, &packet); /*if (twi_master_read(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; }*/ break; case 1: /* if (twi_master_read(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; }*/ break; } if (memcmp(data, expected, 4) == 0) { return ATCA_SUCCESS; } return ATCA_COMM_FAIL; } /** \brief idle CryptoAuth device using I2C bus * \param[in] interface to logical device to idle */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x02; // idle word address value //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 1 }; switch(bus) { case 0: //if (twi_master_write(TWI0, &packet) != TWI_SUCCESS) if (twi_master_write(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; case 1: if (twi_master_write(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; } return ATCA_SUCCESS; } /** \brief sleep CryptoAuth device using I2C bus * \param[in] interface to logical device to sleep */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x01; // sleep word address value //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 1 }; switch(bus) { case 0: //if (twi_master_write(TWI0, &packet) != TWI_SUCCESS) if (twi_master_write(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; case 1: if (twi_master_write(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; } return ATCA_SUCCESS; } /** \brief manages reference count on given bus and releases resource if no more refences exist * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation */ ATCA_STATUS hal_i2c_release( void *hal_data ) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t *)hal_data; i2c_bus_ref_ct--; // track total i2c bus interface instances for consistency checking and debugging // if the use count for this bus has gone to 0 references, disable it. protect against an unbracketed release if (hal && --(hal->ref_ct) <= 0 && i2c_hal_data[hal->bus_index] != NULL) { switch(hal->bus_index) { //case 0: twi_reset(TWI0); break; case 0: twi_reset(TWI_Channel0);break; case 1: twi_reset(TWI_Channel1);break; } free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint32_t twihs_device; uint16_t status; twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = txdata, }; // for this implementation of I2C with CryptoAuth chips, txdata is assumed to have ATCAPacket format // other device types that don't require i/o tokens on the front end of a command need a different hal_i2c_send and wire it up instead of this one // this covers devices such as ATSHA204A and ATECCx08A that require a word address value pre-pended to the packet // txdata[0] is using _reserved byte of the ATCAPacket txdata[0] = 0x03; // insert the Word Address Value, Command token txlength++; // account for word address value byte. packet.length = txlength; if (twihs_master_write( twihs_device, &packet) != STATUS_OK) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief HAL implementation of I2C receive function for ASF I2C * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[in] rxlength ptr to expected number of receive bytes to request * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; int status = !STATUS_OK; Twihs *twihs_device; twihs_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, // use 7-bit address .buffer = rxdata, .length = *rxlength }; twihs_device = i2c_hal_data[bus]->twi_module; while ( retries-- > 0 && status != STATUS_OK ) { if ( twihs_master_read(twihs_device, &packet) != TWIHS_SUCCESS ) status = ATCA_COMM_FAIL; else status = ATCA_SUCCESS; } if ( status != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief method to change the bus speed of I2C * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ ATCA_STATUS change_i2c_speed( ATCAIface iface, uint32_t speed ) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; // if necessary, revert baud rate to what came in. if (twihs_set_speed(i2c_hal_data[bus]->twi_module, speed, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; }
ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t bdrt = cfg->atcai2c.baud; int status = !STATUS_OK; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; if ( bdrt != 100000 ) // if not already at 100KHz, change it change_i2c_speed( iface, 100000 ); // Send the wake by writing to an address of 0x00 twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = 0x00, // TWI slave bus address .buffer = &data[0], // transfer data source buffer .length = 0 // transfer data size (bytes) }; // Send the 00 address as the wake pulse twi_master_write(i2c_hal_data[bus]->i2c_master_instance, &packet ); // part will NACK, so don't check for status atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure packet.chip = cfg->atcai2c.slave_address >> 1; packet.length = 4; packet.buffer = data; while ( retries-- > 0 && status != STATUS_OK ) status = twi_master_read(i2c_hal_data[bus]->i2c_master_instance, &packet); if ( status != STATUS_OK ) return ATCA_COMM_FAIL; // if necessary, revert baud rate to what came in. if ( bdrt != 100000 ) change_i2c_speed( iface, bdrt ); if ( memcmp( data, expected, 4 ) == 0 ) return ATCA_SUCCESS; return ATCA_COMM_FAIL; } /** \brief idle CryptoAuth device using I2C bus * \param[in] iface interface to logical device to idle */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = &data[0], // transfer data source buffer .length = 1 // transfer data size (bytes) }; data[0] = 0x02; // idle word address value if ( twi_master_write((i2c_hal_data[bus]->i2c_master_instance), &packet) != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief sleep CryptoAuth device using I2C bus * \param[in] iface interface to logical device to sleep */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = &data[0], // transfer data source buffer .length = 1 // transfer data size (bytes) }; data[0] = 0x01; // sleep word address value if ( twi_master_write((i2c_hal_data[bus]->i2c_master_instance), &packet) != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief manages reference count on given bus and releases resource if no more refences exist * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation */ ATCA_STATUS hal_i2c_release( void *hal_data ) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data; i2c_bus_ref_ct--; // track total i2c bus interface instances for consistency checking and debugging // if the use count for this bus has gone to 0 references, disable it. protect against an unbracketed release if ( hal && --(hal->ref_ct) <= 0 && i2c_hal_data[hal->bus_index] != NULL ) { twi_master_disable(hal->i2c_master_instance); free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
/** * \brief wake up CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to wakeup * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t bdrt = cfg->atcai2c.baud; int status = !TWI_SUCCESS; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; // if not already at 100kHz, change it if (bdrt != 100000) change_i2c_speed(iface, 100000); // Send 0x00 as wake pulse twi_write_byte(i2c_hal_data[bus]->twi_master_instance, 0x00); // rounded up to the nearest ms atca_delay_ms(((uint32_t)cfg->wake_delay + (1000 - 1)) / 1000); // wait tWHI + tWLO which is configured based on device type and configuration structure twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 4 }; // if necessary, revert baud rate to what came in. if (bdrt != 100000) change_i2c_speed(iface, bdrt); while (retries-- > 0 && status != TWI_SUCCESS) status = twi_master_read(i2c_hal_data[bus]->twi_master_instance, &packet); if (status != TWI_SUCCESS) return ATCA_COMM_FAIL; if (memcmp(data, expected, 4) == 0) return ATCA_SUCCESS; return ATCA_COMM_FAIL; } /** * \brief idle CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to idle * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x02; // idle word address value twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 1 }; if (twi_master_write(i2c_hal_data[bus]->twi_master_instance, &packet) != TWI_SUCCESS) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** * \brief sleep CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to sleep * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x01; // sleep word address value twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 1 }; if (twi_master_write(i2c_hal_data[bus]->twi_master_instance, &packet) != TWI_SUCCESS) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** * \brief manages reference count on given bus and releases resource if no more refences exist * * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_release(void *hal_data) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data; // set to default i2c bus if (hal->bus_index > MAX_I2C_BUSES - 1) hal->bus_index = 0; i2c_bus_ref_ct--; // track total i2c bus interface instances for consistency checking and debugging // if the use count for this bus has gone to 0 references, disable it. protect against an unbracketed release if (hal && --(hal->ref_ct) <= 0 && i2c_hal_data[hal->bus_index] != NULL) { twi_reset(hal->twi_master_instance); free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries, rxlength; uint32_t bdrt = cfg->atcai2c.baud; int status = !STATUS_OK; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; volatile Twihs * twihs_device; twihs_device = i2c_hal_data[bus]->twi_module; if ( bdrt != 100000 ) // if not already at 100KHz, change it if (twihs_set_speed(twihs_device, 100000, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = &data[0], .length = 1 }; twihs_master_write(twihs_device, &packet); atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure // look for wake response rxlength = 4; memset(data, 0x00, rxlength); status = hal_i2c_receive(iface, data, &rxlength ); // if necessary, revert baud rate to what came in. if ( bdrt != 100000) if (twihs_set_speed(twihs_device, bdrt, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; if ( status != STATUS_OK ) return ATCA_COMM_FAIL; if ( memcmp( data, expected, 4 ) == 0 ) return ATCA_SUCCESS; return ATCA_COMM_FAIL; } /** \brief idle CryptoAuth device using I2C bus * \param[in] iface interface to logical device to idle */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; int length; uint32_t twihs_device; uint16_t status; data[0] = 0x02; // idle word address value twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = data, }; packet.length = 1; if (twihs_master_write( twihs_device, &packet) != STATUS_OK) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief sleep CryptoAuth device using I2C bus * \param[in] iface interface to logical device to sleep */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; int length; uint32_t twihs_device; uint16_t status; data[0] = 0x01; // sleep word address value twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = data, }; packet.length = 1; if (twihs_master_write( twihs_device, &packet) != STATUS_OK) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief manages reference count on given bus and releases resource if no more refences exist * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation */ ATCA_STATUS hal_i2c_release( void *hal_data ) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data; i2c_bus_ref_ct--; // track total i2c bus interface instances for consistency checking and debugging // if the use count for this bus has gone to 0 references, disable it. protect against an unbracketed release if ( hal && --(hal->ref_ct) <= 0 && i2c_hal_data[hal->bus_index] != NULL ) { twihs_disable_master_mode( i2c_hal_data[hal->bus_index]->twi_module ); free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = txdata, // transfer data source buffer .length = txlength, // transfer data size (bytes) }; // for this implementation of I2C with CryptoAuth chips, txdata is assumed to have ATCAPacket format // other device types that don't require i/o tokens on the front end of a command need a different hal_i2c_send and wire it up instead of this one // this covers devices such as ATSHA204A and ATECCx08A that require a word address value pre-pended to the packet // txdata[0] is using _reserved byte of the ATCAPacket txdata[0] = 0x03; // insert the Word Address Value, Command token txlength++; // account for word address value byte. packet.length = txlength; if ( twi_master_write(i2c_hal_data[bus]->i2c_master_instance, &packet) != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief HAL implementation of I2C receive function for ASF I2C * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[in] rxlength ptr to expected number of receive bytes to request * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; int status = !STATUS_OK; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = rxdata, // transfer data source buffer .length = *rxlength, // transfer data size (bytes) }; while ( retries-- > 0 && status != STATUS_OK ) status = twi_master_read(i2c_hal_data[bus]->i2c_master_instance, &packet); if ( status != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief method to change the bus speec of I2C * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ void change_i2c_speed( ATCAIface iface, uint32_t speed ) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; config_i2c_master.speed = speed; config_i2c_master.speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), speed); twi_master_disable(i2c_hal_data[bus]->i2c_master_instance); switch (bus) { case 0: i2c_hal_data[bus]->i2c_master_instance = &TWIC; break; case 2: i2c_hal_data[bus]->i2c_master_instance = &TWIE; break; } twi_master_setup((i2c_hal_data[bus]->i2c_master_instance), &config_i2c_master); twi_master_enable(i2c_hal_data[bus]->i2c_master_instance); }
ATCA_STATUS hal_swi_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { #ifdef DEBUG_HAL printf("hal_swi_receive()\r\n"); #endif ATCA_STATUS status = ATCA_COMM_FAIL; ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcaswi.bus; int retries = cfg->rx_retries; uint8_t bit_mask, *head_buff, bit_data; uint16_t i = 0; while ((status != ATCA_SUCCESS) && (retries >= 0x00)) { retries--; head_buff = rxdata; status = hal_swi_send_flag(iface, SWI_FLAG_TX); // Set SWI to receive mode. swi_uart_mode(swi_hal_data[bus], RECEIVE_MODE); #ifdef SAMD21_ASF RX_DELAY #else atca_delay_us(RX_DELAY); // Must be configured to sync with response from device #endif if (status == ATCA_SUCCESS) { for (i = 0; i < *rxlength; i++) { *head_buff = 0x00; for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { bit_data = 0; status = swi_uart_receive_byte(swi_hal_data[bus], &bit_data); if ((i == 0) && (bit_mask == 1) && (status != ATCA_SUCCESS)) break; // Sometimes bit data from device is stretched // When the device sends a "one" bit, it is read as 0x7E or 0x7F. // When the device sends a "zero" bit, it is read as 0x7A, 0x7B, or 7D. if ((bit_data ^ 0x7F) < 2) // Received "one" bit. *head_buff |= bit_mask; } if ((i == 0) && (bit_mask == 1) && (status != ATCA_SUCCESS)) break; head_buff++; } // Set SWI to transmit mode. swi_uart_mode(swi_hal_data[bus], TRANSMIT_MODE); atca_delay_us(TX_DELAY); // Must be configured to sync with response from device } // The Response shorter than expected if ((i >= 4) && (status = ATCA_TIMEOUT)) status = ATCA_SUCCESS; } #ifdef DEBUG_HAL printf("\r\nResponse Packet (size:0x%.4x)\r\n", *rxlength); printf("Count : %.2x\r\n", rxdata[0]); if (rxdata[0] > 3) { printf("Data : "); print_array(&rxdata[1], rxdata[0] - 3); printf("CRC : "); print_array(&rxdata[rxdata[0] - 2], 2); } printf("\r\n"); #endif return status; }