Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MbedTester.cpp Source File

MbedTester.cpp

00001 /*
00002  * Copyright (c) 2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "MbedTester.h"
00019 #include "fpga_config.h"
00020 #include "BlockDevice.h"
00021 #include "rtos/ThisThread.h"
00022 #include "platform/mbed_wait_api.h"
00023 #include "platform/mbed_error.h"
00024 #include "drivers/MbedCRC.h"
00025 
00026 #define mbed_tester_printf(...)
00027 
00028 #define PHYSICAL_PINS           128
00029 #define LOGICAL_PINS            8
00030 #define FIRMWARE_SIZE           2192012
00031 #define FIRMWARE_REGION_SIZE    0x220000
00032 #define FIRMWARE_HEADER_SIZE    0x10000
00033 #define FLASH_SECTOR_SIZE       0x1000
00034 #define LENGTH_SIZE             0x4
00035 #define CRC_SIZE                0x4
00036 #define FLASH_SPI_FREQ_HZ       2000000
00037 #define ANALOG_COUNT            4
00038 
00039 #define PHYSICAL_NC    ((MbedTester::PhysicalIndex)0xFF)
00040 
00041 static const uint8_t KEY[8] = {
00042     0x92, 0x9d, 0x9a, 0x9b,
00043     0x29, 0x35, 0xa2, 0x65
00044 };
00045 
00046 template<size_t width>
00047 class MbedTesterBitMap {
00048 public:
00049 
00050     MbedTesterBitMap()
00051     {
00052         for (size_t i = 0; i < _count; i++) {
00053             _bitmap[i] = 0;
00054         }
00055     }
00056 
00057     bool get(size_t index)
00058     {
00059         if (index >= width) {
00060             return false;
00061         }
00062         return _bitmap[index / 32] & (1 << (index % 32)) ? true : false;
00063     }
00064 
00065     void set(size_t index)
00066     {
00067         if (index >= width) {
00068             return;
00069         }
00070         _bitmap[index / 32] |= 1 << (index % 32);
00071     }
00072 
00073     void clear(size_t index)
00074     {
00075         if (index >= width) {
00076             return;
00077         }
00078         _bitmap[index / 32] &= ~(1 << (index % 32));
00079     }
00080 
00081 private:
00082 
00083     static const size_t _count = (width + 31) / 32;
00084     uint32_t _bitmap[(width + 31) / 32];
00085 };
00086 
00087 static uint8_t spi_transfer(mbed::DigitalInOut *clk, mbed::DigitalInOut *mosi, mbed::DigitalInOut *miso, uint8_t data)
00088 {
00089     uint8_t ret = 0;
00090     for (int i = 0; i < 8; i++) {
00091         *clk = 0;
00092         *mosi = (data >> (7 - i)) & 1;
00093         wait_ns(100);
00094         *clk = 1;
00095         ret |= *miso ? 1 << (7 - i) : 0;
00096         wait_ns(100);
00097     }
00098     return ret;
00099 }
00100 
00101 static void mbed_tester_command(mbed::DigitalInOut *clk, mbed::DigitalInOut *mosi, mbed::DigitalInOut *miso, uint8_t miso_index, uint32_t addr, bool write_n_read, uint8_t *data, uint8_t size)
00102 {
00103     // 8 - Start Key
00104     for (uint32_t i = 0; i < sizeof(KEY); i++) {
00105         spi_transfer(clk, mosi, miso, KEY[i]);
00106     }
00107 
00108     // 1 - Physical pin index for MISO
00109     spi_transfer(clk, mosi, miso, miso_index);
00110 
00111     // 1 - Number of SPI transfers which follow (= N + 5)
00112     spi_transfer(clk, mosi, miso, size + 5);
00113 
00114     // 4 - Little endian address for transfer
00115     spi_transfer(clk, mosi, miso, (addr >> (8 * 0)) & 0xFF);
00116     spi_transfer(clk, mosi, miso, (addr >> (8 * 1)) & 0xFF);
00117     spi_transfer(clk, mosi, miso, (addr >> (8 * 2)) & 0xFF);
00118     spi_transfer(clk, mosi, miso, (addr >> (8 * 3)) & 0xFF);
00119 
00120     // 1 - direction
00121     spi_transfer(clk, mosi, miso, write_n_read ? 1 : 0);
00122 
00123     // N - Data to read or write
00124     if (write_n_read) {//read: false, write: true
00125         for (int i = 0; i < size; i++) {
00126             spi_transfer(clk, mosi, miso, data[i]);
00127         }
00128     } else {
00129         for (int i = 0; i < size; i++) {
00130             data[i] = spi_transfer(clk, mosi, miso, 0);
00131         }
00132     }
00133     *clk = 0;
00134 
00135 }
00136 
00137 static bool mbed_tester_test(mbed::DigitalInOut *clk, mbed::DigitalInOut *mosi, mbed::DigitalInOut *miso, uint8_t miso_index)
00138 {
00139     uint8_t buf[4];
00140     memset(buf, 0, sizeof(buf));
00141     mbed_tester_command(clk, mosi, miso, miso_index, TESTER_CONTROL, false, buf, sizeof(buf));
00142     return memcmp(buf, "mbed", sizeof(buf)) == 0;
00143 }
00144 
00145 
00146 class MbedTesterBlockDevice : public BlockDevice {
00147 public:
00148 
00149     MbedTesterBlockDevice(mbed::DigitalInOut &mosi, mbed::DigitalInOut &miso, mbed::DigitalInOut &clk, mbed::DigitalInOut &cs, uint32_t frequency)
00150         : _mosi(mosi), _miso(miso), _clk(clk), _cs(cs), _wait_ns(1000000000 / frequency / 2), _init(false)
00151     {
00152 
00153         // Set initial values
00154         _cs.write(1);
00155         _clk.write(0);
00156 
00157         // Set direction
00158         _mosi.output();
00159         _miso.input();
00160         _clk.output();
00161         _cs.output();
00162     }
00163 
00164 
00165     virtual int init()
00166     {
00167         if (_check_id()) {
00168             _init = true;
00169         }
00170         return _init ? BD_ERROR_OK : BD_ERROR_DEVICE_ERROR;
00171     }
00172 
00173     virtual int deinit()
00174     {
00175         _init = false;
00176         return BD_ERROR_OK;
00177     }
00178 
00179     virtual int read(void *buffer, bd_addr_t addr, bd_size_t size)
00180     {
00181         if (!is_valid_read(addr, size) || !_init) {
00182             return BD_ERROR_DEVICE_ERROR;
00183         }
00184 
00185         _assert_cs(true);
00186 
00187         uint8_t cmd[] = {
00188             0x0B,                       // Fast read
00189             (uint8_t)(addr >> (2 * 8)), // Address
00190             (uint8_t)(addr >> (1 * 8)),
00191             (uint8_t)(addr >> (0 * 8)),
00192             0x00                        // Dummy
00193         };
00194         _write((char *)cmd, sizeof(cmd), NULL, 0);
00195         _write(NULL, 0, (char *)buffer, size);
00196 
00197         _assert_cs(false);
00198 
00199         return BD_ERROR_OK;
00200     }
00201 
00202     virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size)
00203     {
00204         if (!is_valid_program(addr, size) || !_init) {
00205             return BD_ERROR_DEVICE_ERROR;
00206         }
00207 
00208         const bd_size_t max_program_size = 256;
00209         bd_size_t programmed = 0;
00210         while (programmed < size) {
00211             const bd_size_t size_left = size - programmed;
00212             const bd_size_t program_size = size_left < max_program_size ? size_left : max_program_size;
00213 
00214             _write_enable();
00215             _page_program(addr + programmed, (const uint8_t *)buffer, program_size);
00216             _wait_ready();
00217             programmed += program_size;
00218         }
00219 
00220         return BD_ERROR_OK;
00221     }
00222 
00223     virtual int erase(bd_addr_t addr, bd_size_t size)
00224     {
00225         if (!is_valid_erase(addr, size) || !_init) {
00226             return BD_ERROR_DEVICE_ERROR;
00227         }
00228 
00229         if ((addr == 0) && (size == FLASH_SECTOR_SIZE)) {
00230             // Allow 4K erase only on the first sector. The flash on the basys3 does
00231             // not allow sector erases at the higher addresses.
00232             _write_enable();
00233             _sector_erase(addr);
00234             _wait_ready();
00235             return BD_ERROR_OK;
00236         }
00237 
00238         if (!is_valid_erase(addr, size)) {
00239             return BD_ERROR_DEVICE_ERROR;
00240         }
00241 
00242         const uint32_t erase_size = get_erase_size();
00243         bd_size_t erased = 0;
00244         while (erased < erase_size) {
00245             _write_enable();
00246             _block_erase(addr + erased);
00247             _wait_ready();
00248             erased += erase_size;
00249         }
00250         return BD_ERROR_OK;
00251     }
00252 
00253     virtual bd_size_t get_read_size() const
00254     {
00255         return 1;
00256     }
00257 
00258     virtual bd_size_t get_program_size() const
00259     {
00260         return 1;
00261     }
00262 
00263     virtual bd_size_t get_erase_size() const
00264     {
00265         return 0x10000;
00266     }
00267 
00268     virtual bd_size_t get_erase_size(bd_addr_t addr) const
00269     {
00270         return get_erase_size();
00271     }
00272 
00273     virtual bd_size_t size() const
00274     {
00275         return 8 * 1024 * 1024;
00276     }
00277 
00278     virtual const char *get_type() const
00279     {
00280         return "MbedTesterBlockDevice";
00281     }
00282 
00283 protected:
00284 
00285     void _write_enable()
00286     {
00287         uint8_t command[1];
00288 
00289         _assert_cs(true);
00290 
00291         command[0] = 0x06;
00292         _write((char *)command, 1, NULL, 0);
00293 
00294         _assert_cs(false);
00295     }
00296 
00297     void _sector_erase(uint32_t addr)
00298     {
00299         uint8_t command[4];
00300 
00301         _assert_cs(true);
00302 
00303         command[0] = 0x20;
00304         command[1] = (addr >> (2 * 8)) & 0xFF;
00305         command[2] = (addr >> (1 * 8)) & 0xFF;
00306         command[3] = (addr >> (0 * 8)) & 0xFF;
00307         _write((char *)command, 4, NULL, 0);
00308 
00309         _assert_cs(false);
00310     }
00311 
00312     void _block_erase(uint32_t addr)
00313     {
00314         uint8_t command[4];
00315 
00316         _assert_cs(true);
00317 
00318         command[0] = 0xD8;
00319         command[1] = (addr >> (2 * 8)) & 0xFF;
00320         command[2] = (addr >> (1 * 8)) & 0xFF;
00321         command[3] = (addr >> (0 * 8)) & 0xFF;
00322         _write((char *)command, 4, NULL, 0);
00323 
00324         _assert_cs(false);
00325     }
00326 
00327     void _page_program(uint32_t addr, const uint8_t *data, uint32_t size)
00328     {
00329         uint8_t command[4];
00330 
00331         _assert_cs(true);
00332 
00333         command[0] = 0x02;
00334         command[1] = (addr >> (2 * 8)) & 0xFF;
00335         command[2] = (addr >> (1 * 8)) & 0xFF;
00336         command[3] = (addr >> (0 * 8)) & 0xFF;
00337         _write((char *)command, 4, NULL, 0);
00338         _write((char *)data, size, NULL, 0);
00339 
00340         _assert_cs(false);
00341     }
00342 
00343     void _wait_ready()
00344     {
00345         uint8_t command[2];
00346         uint8_t response[2];
00347 
00348         // Wait for ready
00349         response[1] = 0xFF;
00350         do {
00351             _assert_cs(true);
00352 
00353             command[0] = 0x05;
00354             command[1] = 0;
00355             _write((char *)command, 2, (char *)response, 2);
00356 
00357             _assert_cs(false);
00358 
00359         } while (response[1] & (1 << 0));
00360     }
00361 
00362     bool _check_id()
00363     {
00364         uint8_t command[1];
00365         char id0[3];
00366         char id1[3];
00367 
00368         // Read ID twice and verify it is the same
00369 
00370         _assert_cs(true);
00371 
00372         command[0] = 0x9F;
00373         _write((char *)command, 1, NULL, 0);
00374         _write(NULL, 0, id0, sizeof(id0));
00375 
00376         _assert_cs(false);
00377 
00378         _assert_cs(true);
00379 
00380         command[0] = 0x9F;
00381         _write((char *)command, 1, NULL, 0);
00382         _write(NULL, 0, id1, sizeof(id1));
00383 
00384         _assert_cs(false);
00385 
00386         // Return failure if IDs are not the same
00387         for (size_t i = 0; i < sizeof(id0); i++) {
00388             if (id0[i] != id1[i]) {
00389                 return false;
00390             }
00391         }
00392 
00393         // If all 0xFF return failure
00394         if ((id0[0] == 0xFF) && (id0[1] == 0xFF) && (id0[2] == 0xFF)) {
00395             return false;
00396         }
00397 
00398         // If all 0x00 return failure
00399         if ((id0[0] == 0x00) && (id0[1] == 0x00) && (id0[2] == 0x00)) {
00400             return false;
00401         }
00402 
00403         return true;
00404     }
00405 
00406     void _write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
00407     {
00408         int transfers = 0;
00409         if (tx_length > transfers) {
00410             transfers = tx_length;
00411         }
00412         if (rx_length > transfers) {
00413             transfers = rx_length;
00414         }
00415 
00416         for (int i = 0; i < transfers; i++) {
00417             uint8_t out = i < tx_length ? tx_buffer[i] : 0;
00418             uint8_t in = 0;
00419             for (int j = 0; j < 8; j++) {
00420                 _mosi.write((out >> 7) & 1);
00421                 out = out << 1;
00422                 wait_ns(_wait_ns);
00423 
00424                 _clk.write(1);
00425                 in = (in << 1) | (_miso.read() ? 1 : 0);
00426                 wait_ns(_wait_ns);
00427 
00428                 _clk.write(0);
00429             }
00430             if (i < rx_length) {
00431                 rx_buffer[i] = in;
00432             }
00433         }
00434     }
00435 
00436     void _assert_cs(bool asserted)
00437     {
00438         _clk = 0;
00439         wait_ns(_wait_ns);
00440         _cs = asserted ? 0 : 1;
00441         wait_ns(_wait_ns);
00442     }
00443 
00444     mbed::DigitalInOut &_mosi;
00445     mbed::DigitalInOut &_miso;
00446     mbed::DigitalInOut &_clk;
00447     mbed::DigitalInOut &_cs;
00448     uint32_t _wait_ns;
00449     bool _init;
00450 };
00451 
00452 static void dummy_progress(uint8_t)
00453 {
00454     // Stub progress handler for firmware update/dump
00455 }
00456 
00457 // Header taken from app note XAPP1081. Information on the commands
00458 // can be found in the 7 Series FPGA configuration user guide - UG470
00459 static const uint8_t BANK_B_SELECT[] = {
00460     0x20, 0x00, 0x00, 0x00,     // 0x20000000   NOP
00461     0x30, 0x02, 0x00, 0x01,     // 0x30020001   WRITE to WBSTAR (Warm boot start address register)
00462     0x00, 0x23, 0x00, 0x00,     // 0x00230000       0x230000 = Second bank start address
00463     0x30, 0x00, 0x80, 0x01,     // 0x30008001   WRITE to CMD register
00464     0x00, 0x00, 0x00, 0x0F,     // 0x0000000F       0x0F = IPROG command (starts warm boot)
00465     0x20, 0x00, 0x00, 0x00,     // 0x20000000   NOP
00466     0x20, 0x00, 0x00, 0x00,     // 0x20000000   NOP
00467     0x20, 0x00, 0x00, 0x00      // 0x20000000   NOP
00468 };
00469 
00470 static const uint8_t SYNC_WORD[] = {
00471     0xAA, 0x99, 0x55, 0x66      // 0xAA995566   Sync word
00472 };
00473 
00474 static bool _firmware_header_valid(BlockDevice &flash, bool &valid)
00475 {
00476     uint8_t buf[64];
00477     size_t pos = 0;
00478     size_t read_size;
00479 
00480     // Default to invalid
00481     valid = false;
00482 
00483     // Check that first portion is erased
00484     while (pos < FLASH_SECTOR_SIZE - sizeof(SYNC_WORD)) {
00485         read_size = FLASH_SECTOR_SIZE - pos;
00486         if (read_size > sizeof(buf)) {
00487             read_size = sizeof(buf);
00488         }
00489         if (flash.read(buf, pos, read_size) != BD_ERROR_OK) {
00490             return false;
00491         }
00492         pos += read_size;
00493         for (size_t i = 0; i < read_size; i++) {
00494             if (buf[i] != 0xFF) {
00495                 valid = false;
00496                 return true;
00497             }
00498         }
00499     }
00500 
00501     // Skip the sync word
00502     pos += sizeof(SYNC_WORD);
00503 
00504     // Check that BANK_B_SELECT is valid
00505     read_size = sizeof(BANK_B_SELECT);
00506     if (flash.read(buf, pos, read_size) != BD_ERROR_OK) {
00507         return false;
00508     }
00509     pos += read_size;
00510     if (memcmp(buf, BANK_B_SELECT, sizeof(BANK_B_SELECT)) != 0) {
00511         valid = false;
00512         return true;
00513     }
00514 
00515     // Check if the rest is 0xFF
00516     while (pos < FIRMWARE_HEADER_SIZE) {
00517         read_size = FIRMWARE_HEADER_SIZE - pos;
00518         if (read_size > sizeof(buf)) {
00519             read_size = sizeof(buf);
00520         }
00521         if (flash.read(buf, pos, read_size) != BD_ERROR_OK) {
00522             return false;
00523         }
00524         pos += read_size;
00525         for (size_t i = 0; i < read_size; i++) {
00526             if (buf[i] != 0xFF) {
00527                 valid = false;
00528                 return true;
00529             }
00530         }
00531     }
00532 
00533     valid = true;
00534     return true;
00535 }
00536 
00537 static bool _firmware_get_active_bank(BlockDevice &flash, bool &second_bank_active)
00538 {
00539     uint8_t buf[sizeof(SYNC_WORD)];
00540 
00541     if (flash.read(buf, FLASH_SECTOR_SIZE - sizeof(SYNC_WORD), sizeof(SYNC_WORD)) != BD_ERROR_OK) {
00542         return false;
00543     }
00544 
00545     second_bank_active = memcmp(buf, SYNC_WORD, sizeof(SYNC_WORD)) == 0 ? true : false;
00546     return true;
00547 }
00548 
00549 static bool _firmware_set_active_bank(BlockDevice &flash, bool second_bank)
00550 {
00551     bool valid = false;
00552     if (!_firmware_header_valid(flash, valid)) {
00553         return false;
00554     }
00555     if (!valid) {
00556         if (flash.erase(0, FIRMWARE_HEADER_SIZE) != BD_ERROR_OK) {
00557             return false;
00558         }
00559         if (flash.program(BANK_B_SELECT, FLASH_SECTOR_SIZE, sizeof(BANK_B_SELECT)) != BD_ERROR_OK) {
00560             return false;
00561         }
00562     }
00563     if (!flash.erase(0, FLASH_SECTOR_SIZE)) {
00564         return false;
00565     }
00566 
00567 
00568     if (second_bank) {
00569         // Write the sync word. Before the sync word is written the FPGA will boot from the first bank.
00570         // After the sync word is written the FPGA will boot from the second bank.
00571         if (flash.program(SYNC_WORD, FLASH_SECTOR_SIZE - sizeof(SYNC_WORD), sizeof(SYNC_WORD)) != BD_ERROR_OK) {
00572             return false;
00573         }
00574     }
00575 
00576     return true;
00577 }
00578 
00579 MbedTester::MbedTester(const PinList *form_factor, const PinList *exclude_pins)
00580     : _form_factor(form_factor), _exclude_pins(exclude_pins), _control_auto(true), _control_valid(false),
00581       _clk_index(PHYSICAL_NC), _mosi_index(PHYSICAL_NC), _miso_index(PHYSICAL_NC), _aux_index(PHYSICAL_NC),
00582       _clk(NULL), _mosi(NULL), _miso(NULL), _aux(NULL)
00583 {
00584     _reset();
00585     _init_io_exp_rst_flag = 0;
00586 }
00587 
00588 MbedTester::~MbedTester()
00589 {
00590     _free_control_pins();
00591 }
00592 
00593 
00594 void MbedTester::set_control_pins_auto()
00595 {
00596     _control_auto = true;
00597 }
00598 
00599 void MbedTester::set_control_pins_manual(PinName clk, PinName mosi, PinName miso, PinName aux)
00600 {
00601     int index;
00602     index = _form_factor.index(clk);
00603     if (index < 0) {
00604         error("Invalid CLK index");
00605     }
00606     PhysicalIndex clk_index = index;
00607 
00608     index = _form_factor.index(mosi);
00609     if (index < 0) {
00610         error("Invalid MOSI index");
00611     }
00612     PhysicalIndex mosi_index = index;
00613 
00614     index = _form_factor.index(miso);
00615     if (index < 0) {
00616         error("Invalid MISO index");
00617     }
00618     PhysicalIndex miso_index = index;
00619 
00620     index = _form_factor.index(aux);
00621     if (index < 0) {
00622         error("Invalid AUX index");
00623     }
00624     PhysicalIndex aux_index = index;
00625 
00626     if (clk_index + 1 != mosi_index) {
00627         error("MOSI pin index does not follow CLK as required");
00628     }
00629 
00630     if ((miso_index == clk_index) || (miso_index == mosi_index)) {
00631         error("MISO conflicts with a control channel");
00632     }
00633     if ((aux_index == clk_index) || (aux_index == mosi_index) || (aux_index == miso_index)) {
00634         error("AUX conflicts with a control channel");
00635     }
00636 
00637     // All criteria have been met so set the pins
00638     _control_auto = false;
00639     _free_control_pins();
00640     _clk_index = clk_index;
00641     _mosi_index = mosi_index;
00642     _miso_index = miso_index;
00643     _aux_index = aux_index;
00644     _setup_control_pins();
00645     _control_valid = true;
00646 }
00647 
00648 bool MbedTester::firmware_dump(mbed::FileHandle *dest, mbed::Callback<void(uint8_t)> progress)
00649 {
00650     _update_control_pins();
00651 
00652     if (!progress) {
00653         progress = mbed::callback(dummy_progress);
00654     }
00655 
00656     // Mapping intentionally different from control channel to prevent
00657     // unintentional activation (clk and mosi flipped)
00658     MbedTesterBlockDevice flash(*_clk, *_miso, *_mosi, *_aux, FLASH_SPI_FREQ_HZ);
00659     sys_pin_mode_spi_serial_flash(_clk_index, _miso_index, _mosi_index, _aux_index);
00660 
00661     progress(0);
00662 
00663     if (flash.init() != BD_ERROR_OK) {
00664         sys_pin_mode_disabled();
00665         return false;
00666     }
00667 
00668     // Set the start of dump to the active bank
00669     bool second_bank_active;
00670     if (!_firmware_get_active_bank(flash, second_bank_active)) {
00671         // Error determining active bank
00672         sys_pin_mode_disabled();
00673         return false;
00674     }
00675     const uint32_t start = FIRMWARE_HEADER_SIZE + (second_bank_active ? FIRMWARE_REGION_SIZE : 0);
00676 
00677     // Get the firmware size
00678     uint32_t offset = 0;
00679     uint8_t buf[256];
00680     uint32_t prev_percent_done = 0;
00681     if (flash.read(buf, start + offset, LENGTH_SIZE) != BD_ERROR_OK) {
00682         sys_pin_mode_disabled();
00683         return false;
00684     }
00685     if (dest->write(buf, LENGTH_SIZE) != LENGTH_SIZE) {
00686         sys_pin_mode_disabled();
00687         return false;
00688     }
00689     offset += LENGTH_SIZE;
00690     uint32_t data_size = (buf[0] << (0 * 8)) |
00691                          (buf[1] << (1 * 8)) |
00692                          (buf[2] << (2 * 8)) |
00693                          (buf[3] << (3 * 8));
00694     if (data_size > FIRMWARE_REGION_SIZE - LENGTH_SIZE - CRC_SIZE) {
00695         data_size = FIRMWARE_REGION_SIZE - LENGTH_SIZE - CRC_SIZE;
00696     }
00697     const uint32_t firmware_size = data_size + LENGTH_SIZE + CRC_SIZE;
00698 
00699     // Dump firmware
00700     while (offset < firmware_size) {
00701         uint32_t read_size = firmware_size - offset;
00702         if (read_size > sizeof(buf)) {
00703             read_size = sizeof(buf);
00704         }
00705         if (flash.read(buf, start + offset, read_size) != BD_ERROR_OK) {
00706             sys_pin_mode_disabled();
00707             return false;
00708         }
00709         ssize_t write_size = dest->write(buf, read_size);
00710         if ((uint32_t)write_size != read_size) {
00711             sys_pin_mode_disabled();
00712             return false;
00713         }
00714         offset += read_size;
00715 
00716         const uint8_t percent_done = (offset * 100) / firmware_size;
00717         if (percent_done != prev_percent_done) {
00718             progress(percent_done);
00719             prev_percent_done = percent_done;
00720         }
00721     }
00722 
00723     progress(100);
00724 
00725     sys_pin_mode_disabled();
00726     return true;
00727 }
00728 
00729 bool MbedTester::firmware_dump_all(mbed::FileHandle *dest, mbed::Callback<void(uint8_t)> progress)
00730 {
00731     _update_control_pins();
00732 
00733     if (!progress) {
00734         progress = mbed::callback(dummy_progress);
00735     }
00736 
00737     // Mapping intentionally different from control channel to prevent
00738     // unintentional activation (clk and mosi flipped)
00739     MbedTesterBlockDevice flash(*_clk, *_miso, *_mosi, *_aux, FLASH_SPI_FREQ_HZ);
00740     sys_pin_mode_spi_serial_flash(_clk_index, _miso_index, _mosi_index, _aux_index);
00741 
00742     progress(0);
00743 
00744     if (flash.init() != BD_ERROR_OK) {
00745         sys_pin_mode_disabled();
00746         return false;
00747     }
00748 
00749     uint32_t pos = 0;
00750     uint8_t buf[256];
00751     uint32_t prev_percent_done = 0;
00752     const uint32_t total_size = flash.size();
00753     while (pos < total_size) {
00754         uint32_t read_size = total_size - pos;
00755         if (read_size > sizeof(buf)) {
00756             read_size = sizeof(buf);
00757         }
00758         if (flash.read(buf, pos, read_size) != BD_ERROR_OK) {
00759             sys_pin_mode_disabled();
00760             return false;
00761         }
00762         ssize_t write_size = dest->write(buf, read_size);
00763         if ((uint32_t)write_size != read_size) {
00764             sys_pin_mode_disabled();
00765             return false;
00766         }
00767         pos += read_size;
00768 
00769         const uint8_t percent_done = (pos * 100) / total_size;
00770         if (percent_done != prev_percent_done) {
00771             progress(percent_done);
00772             prev_percent_done = percent_done;
00773         }
00774     }
00775 
00776     progress(100);
00777 
00778     sys_pin_mode_disabled();
00779     return true;
00780 }
00781 
00782 bool MbedTester::firmware_update(mbed::FileHandle *src, mbed::Callback<void(uint8_t)> progress)
00783 {
00784     _update_control_pins();
00785 
00786     if (!progress) {
00787         progress = mbed::callback(dummy_progress);
00788     }
00789 
00790     // Mapping intentionally different from control channel to prevent
00791     // unintentional activation (clk and mosi flipped)
00792     MbedTesterBlockDevice flash(*_clk, *_miso, *_mosi, *_aux, FLASH_SPI_FREQ_HZ);
00793     sys_pin_mode_spi_serial_flash(_clk_index, _miso_index, _mosi_index, _aux_index);
00794 
00795     progress(0);
00796 
00797     if (flash.init() != BD_ERROR_OK) {
00798         sys_pin_mode_disabled();
00799         return false;
00800     }
00801 
00802     // Validate file size
00803     const uint32_t file_size = src->size();
00804     if (file_size > FIRMWARE_REGION_SIZE) {
00805         // Firmware image too big
00806         sys_pin_mode_disabled();
00807         return false;
00808     }
00809     if (file_size < LENGTH_SIZE + CRC_SIZE) {
00810         // Firmware image too small
00811         sys_pin_mode_disabled();
00812         return false;
00813     }
00814 
00815     // Set the start of programming to the inactive bank
00816     bool second_bank_active;
00817     if (!_firmware_get_active_bank(flash, second_bank_active)) {
00818         // Error determining active bank
00819         sys_pin_mode_disabled();
00820         return false;
00821     }
00822     const uint32_t start = FIRMWARE_HEADER_SIZE + (second_bank_active ? 0 : FIRMWARE_REGION_SIZE);
00823 
00824     // Setup CRC calculation
00825     uint32_t crc;
00826     mbed::MbedCRC<POLY_32BIT_ANSI, 32> ct;
00827     if (ct.compute_partial_start(&crc) != 0) {
00828         sys_pin_mode_disabled();
00829         return false;
00830     }
00831 
00832     uint8_t buf[256];
00833     const bd_size_t erase_size = flash.get_erase_size();
00834     uint32_t offset = 0;
00835     uint32_t prev_percent_done = 0;
00836     uint32_t stored_crc = 0;
00837     bool size_valid = false;
00838     while (offset < file_size) {
00839 
00840         // Prepare data
00841         uint32_t program_size = file_size - offset;
00842         if (program_size > sizeof(buf)) {
00843             program_size = sizeof(buf);
00844         }
00845         ssize_t read_size = src->read(buf, program_size);
00846         if (read_size < 0) {
00847             sys_pin_mode_disabled();
00848             return false;
00849         } else if (read_size == 0) {
00850             break;
00851         }
00852         program_size = read_size;
00853 
00854         // Record values and calculate checksum
00855         uint32_t crc_offset = 0;
00856         uint32_t crc_size = program_size;
00857         if (offset == 0) {
00858             // Overlap with the size field
00859 
00860             // Check that the data length is correct
00861             const size_t data_size = (buf[0] << (0 * 8)) |
00862                                      (buf[1] << (1 * 8)) |
00863                                      (buf[2] << (2 * 8)) |
00864                                      (buf[3] << (3 * 8));
00865             if (data_size != file_size - LENGTH_SIZE - CRC_SIZE) {
00866                 // Invalid data length
00867                 sys_pin_mode_disabled();
00868                 return false;
00869             }
00870             size_valid = true;
00871 
00872             // Don't include the length in the checksum
00873             crc_offset += LENGTH_SIZE;
00874             crc_size -= LENGTH_SIZE;
00875         }
00876         if (offset + program_size > file_size - CRC_SIZE) {
00877             // Overlap with the CRC field
00878             for (uint32_t i = 0; i < CRC_SIZE; i++) {
00879                 uint32_t byte_offset = file_size - CRC_SIZE + i;
00880                 if ((byte_offset >= offset) && (byte_offset < offset + program_size)) {
00881                     uint32_t buf_pos = byte_offset - offset;
00882                     stored_crc |= buf[buf_pos] << (i * 8);
00883 
00884                     // Don't include the stored CRC in the CRC
00885                     crc_size--;
00886                 }
00887             }
00888         }
00889         if (ct.compute_partial(buf + crc_offset, crc_size, &crc) != 0) {
00890             sys_pin_mode_disabled();
00891             return false;
00892         }
00893 
00894         // Write data to file
00895         const uint32_t addr = start + offset;
00896         if (addr % erase_size == 0) {
00897             if (flash.erase(addr, erase_size) != BD_ERROR_OK) {
00898                 sys_pin_mode_disabled();
00899                 return false;
00900             }
00901         }
00902         if (flash.program(buf, addr, read_size) != BD_ERROR_OK) {
00903             sys_pin_mode_disabled();
00904             return false;
00905         }
00906 
00907         offset += program_size;
00908 
00909         const uint8_t percent_done = (offset * 100) / file_size;
00910         if (percent_done != prev_percent_done) {
00911             progress(percent_done);
00912             prev_percent_done = percent_done;
00913         }
00914     }
00915 
00916     // Check that everything was good and if so switch active bank
00917     if (!size_valid) {
00918         sys_pin_mode_disabled();
00919         return false;
00920     }
00921     if (ct.compute_partial_stop(&crc) != 0) {
00922         sys_pin_mode_disabled();
00923         return false;
00924     }
00925     if (crc != stored_crc) {
00926         sys_pin_mode_disabled();
00927         return false;
00928     }
00929     if (!_firmware_set_active_bank(flash, !second_bank_active)) {
00930         sys_pin_mode_disabled();
00931         return false;
00932     }
00933 
00934     progress(100);
00935 
00936     sys_pin_mode_disabled();
00937     return true;
00938 }
00939 
00940 void MbedTester::pin_map_set(PinName physical, LogicalPin logical)
00941 {
00942     int index = _form_factor.index(physical);
00943     if (index < 0) {
00944         error("Pin %i not in form factor", physical);
00945         return;
00946     }
00947     if (logical >= LogicalPinTotal) {
00948         error("Invalid logical pin %i", logical);
00949         return;
00950     }
00951     pin_map_index(index, logical);
00952 }
00953 
00954 void MbedTester::pin_map_reset()
00955 {
00956     for (uint32_t i = 0; i < sizeof(_mapping) / sizeof(_mapping[0]); i++) {
00957         _mapping[i] = PHYSICAL_NC;
00958     }
00959 
00960     uint8_t pin_buf[PHYSICAL_PINS + LOGICAL_PINS];
00961     memset(pin_buf, 0xFF, sizeof(pin_buf));
00962     write(TESTER_REMAP, pin_buf, sizeof(pin_buf));
00963 }
00964 
00965 void MbedTester::peripherals_reset()
00966 {
00967     uint8_t buf = TESTER_CONTROL_RESET_PERIPHERALS;
00968     write(TESTER_CONTROL_RESET, &buf, sizeof(buf));
00969 }
00970 
00971 void MbedTester::reset()
00972 {
00973     // Reset pullup settings
00974     pin_pull_reset_all();
00975 
00976     // Reset the FPGA
00977     uint8_t buf = TESTER_CONTROL_RESET_ALL;
00978     write(TESTER_CONTROL_RESET, &buf, sizeof(buf));
00979 
00980     // Reset the pinmap
00981     // NOTE - this is only needed for compatibility with
00982     //        older firmware which resets the mapping
00983     //        of all pins to 0x00 rather than 0xFF.
00984     pin_map_reset();
00985 
00986     // Reset internal state variables
00987     _reset();
00988 }
00989 
00990 void MbedTester::reprogram()
00991 {
00992     // Trigger reprogramming
00993     uint8_t buf = TESTER_CONTROL_REPROGRAM;
00994     write(TESTER_CONTROL_RESET, &buf, sizeof(buf));
00995 
00996     // Reset internal state variables
00997     _reset();
00998 }
00999 
01000 uint32_t MbedTester::version()
01001 {
01002     uint32_t software_version;
01003 
01004     read(TESTER_CONTROL_VERSION, (uint8_t *)&software_version, sizeof(software_version));
01005 
01006     return software_version;
01007 }
01008 
01009 void MbedTester::select_peripheral(Peripheral peripheral)
01010 {
01011     uint8_t data = peripheral;
01012     write(TESTER_PERIPHERAL_SELECT, &data, sizeof(data));
01013 }
01014 
01015 void MbedTester::pin_pull_reset_all()
01016 {
01017     _init_io_exp_rst_flag = 1;
01018     sys_pin_write(I2CReset, 0, true);
01019     wait_us(1);
01020     sys_pin_write(I2CReset, 0, false);
01021 }
01022 
01023 int MbedTester::pin_set_pull(PinName pin, PullMode mode)
01024 {
01025     int index = _form_factor.index(pin);
01026     if ((index < 0) || (index > 127)) {
01027         error("Pin %i not in form factor", pin);
01028         return -1;
01029     }
01030 
01031     return pin_set_pull_index(index, mode);
01032 }
01033 
01034 int MbedTester::pin_set_pull_index(int index, PullMode mode)
01035 {
01036     // Reset IO expanders once after Mbed reset if user attempts
01037     // to read/write them without explicitly reseting them
01038     if (_init_io_exp_rst_flag == 0) {
01039         pin_pull_reset_all();
01040     }
01041     uint8_t chip_num;//can be 0-5
01042     uint16_t dev_addr;//can be 0x44 or 0x46
01043     uint8_t port_num;//can be 0-23
01044     uint8_t output_port_reg;//can be 4, 5, or 6
01045     uint8_t config_reg;//can be 12, 13, or 14
01046     uint8_t reg_bit;//can be 0-7
01047     uint8_t cmd0[2];//for writing configuration register
01048     uint8_t cmd1[2];//for writing output port register
01049     uint8_t i2c_index;//can be 0, 1, or 2 for TESTER_SYS_IO_MODE_I2C_IO_EXPANDER0/1/2
01050 
01051     chip_num = index / 24;
01052     if ((chip_num == 0) || (chip_num == 1)) {
01053         i2c_index = 0;
01054     } else if ((chip_num == 2) || (chip_num == 3)) {
01055         i2c_index = 1;
01056     } else if ((chip_num == 4) || (chip_num == 5)) {
01057         i2c_index = 2;
01058     } else {
01059         error("Corrupt index %i, should be 0-127\r\n", index);
01060         return -1;
01061     }
01062     dev_addr = (chip_num % 2) ? 0x44 : 0x46;
01063     port_num = index % 24;
01064     output_port_reg = 4 + (port_num / 8);
01065     config_reg = 12 + (port_num / 8);
01066     reg_bit = port_num % 8;
01067 
01068     uint8_t read_config_byte[1];
01069     uint8_t read_output_byte[1];
01070     if (io_expander_i2c_read(i2c_index, dev_addr, config_reg, read_config_byte, 1) != 0) {
01071         return -1;
01072     }
01073     if (io_expander_i2c_read(i2c_index, dev_addr, output_port_reg, read_output_byte, 1) != 0) {
01074         return -1;
01075     }
01076     cmd0[0] = config_reg;
01077     if ((mode == PullDown) || (mode == PullUp)) {
01078         cmd0[1] = read_config_byte[0] & ~(1 << reg_bit);
01079         cmd1[0] = output_port_reg;
01080         if (mode == PullDown) {
01081             cmd1[1] = read_output_byte[0] & ~(1 << reg_bit);
01082         } else if (mode == PullUp) {
01083             cmd1[1] = read_output_byte[0] | (1 << reg_bit);
01084         }
01085     } else if (mode == PullNone) {
01086         cmd0[1] = read_config_byte[0] | (1 << reg_bit);
01087     }
01088 
01089     //write configuration register for all 3 modes
01090     if (io_expander_i2c_write(i2c_index, dev_addr, cmd0, 2) != 0) {
01091         return -1;
01092     }
01093     //only write output register for pulldown and pullup
01094     if ((mode == PullDown) || (mode == PullUp)) {
01095         if (io_expander_i2c_write(i2c_index, dev_addr, cmd1, 2) != 0) {
01096             return -1;
01097         }
01098     }
01099     return 0;
01100 }
01101 
01102 uint8_t MbedTester::io_expander_read(PinName pin, IOExpanderReg reg_type)
01103 {
01104     int index = _form_factor.index(pin);
01105 
01106     return io_expander_read_index(index, reg_type);
01107 }
01108 
01109 uint8_t MbedTester::io_expander_read_index(int index, IOExpanderReg reg_type)
01110 {
01111     // Reset IO expanders once after Mbed reset if user attempts
01112     // to read/write them without explicitly reseting them
01113     if (_init_io_exp_rst_flag == 0) {
01114         pin_pull_reset_all();
01115     }
01116     uint8_t read_byte[1] = {0};
01117     uint8_t chip_num;//can be 0-5
01118     uint16_t dev_addr;//can be 0x44 or 0x46
01119     uint8_t port_num;//can be 0-23
01120     uint8_t input_port_reg;//can be 0, 1, or 2
01121     uint8_t output_port_reg;//can be 4, 5, or 6
01122     uint8_t config_reg;//can be 12, 13, or 14
01123     uint8_t reg_bit;//can be 0-7
01124     uint8_t i2c_index;
01125 
01126     chip_num = index / 24;
01127     if ((chip_num == 0) || (chip_num == 1)) {
01128         i2c_index = 0;
01129     } else if ((chip_num == 2) || (chip_num == 3)) {
01130         i2c_index = 1;
01131     } else if ((chip_num == 4) || (chip_num == 5)) {
01132         i2c_index = 2;
01133     } else {
01134         i2c_index = 0xFF;
01135         error("Invalid pin index, index should be in the range of 0-127");
01136     }
01137     dev_addr = (chip_num % 2) ? 0x44 : 0x46;
01138     port_num = index % 24;
01139     input_port_reg = (port_num / 8);
01140     output_port_reg = 4 + (port_num / 8);
01141     config_reg = 12 + (port_num / 8);
01142     reg_bit = port_num % 8;
01143     uint8_t reg;
01144     if (reg_type == RegInput) {
01145         reg = input_port_reg;
01146     } else if (reg_type == RegOutput) {
01147         reg = output_port_reg;
01148     } else if (reg_type == RegConfig) {
01149         reg = config_reg;
01150     } else {
01151         reg = 0xFF;
01152         error("Invalid register type, should be: INPUT, OUTPUT, or RegConfig");
01153     }
01154 
01155     int read_success = io_expander_i2c_read(i2c_index, dev_addr, reg, read_byte, 1);
01156     MBED_ASSERT(read_success == 0);
01157     uint8_t bit = (read_byte[0] & (1 << reg_bit)) >> reg_bit;
01158     return bit;
01159 }
01160 
01161 int MbedTester::io_expander_i2c_read(uint8_t i2c_index, uint8_t dev_addr, uint8_t start_reg, uint8_t *data, int length)
01162 {
01163     _update_control_pins();
01164     //sda_in = _miso_index
01165     //sda_val = _aux_index
01166     //scl_in = _mosi_index (PHYSICAL_NC)
01167     //scl_val = _clk_index
01168     mbed::DigitalInOut *sda_in = _miso;
01169     mbed::DigitalInOut *sda_val = _aux;
01170     mbed::DigitalInOut *scl_val = _clk;
01171     sda_in->input();
01172     sda_val->output();
01173     *sda_val = 1;
01174     scl_val->output();
01175     sys_pin_mode_i2c_io_expander(i2c_index, _miso_index, _aux_index, PHYSICAL_NC, _clk_index);
01176 
01177     //start condition
01178     *scl_val = 1;
01179     wait_ns(2500);
01180     *sda_val = 0;
01181     wait_ns(2500);
01182 
01183     // begin writing data, dev_addr first
01184     uint8_t send_bit;
01185     for (int j = 0; j < 2; j += 1) {
01186         *scl_val = 0;
01187         *sda_val = 0;
01188         wait_ns(2500);
01189         for (int i = 7; i > -1; i -= 1) {
01190             if (j == 0) {
01191                 send_bit = (dev_addr & (1 << i)) >> i;
01192             } else {
01193                 send_bit = (start_reg & (1 << i)) >> i;
01194             }
01195             *sda_val = send_bit;
01196             wait_ns(500);
01197 
01198             *scl_val = 1;
01199             wait_ns(2500);
01200             *scl_val = 0;
01201             wait_ns(1000);
01202             *sda_val = 0;
01203             wait_ns(1000);
01204         }
01205         // receive ACK from IO extender
01206         *sda_val = 1;//make sda high z to receive ACK
01207         //clk the ACK
01208         *scl_val = 1;
01209         //read sda to check for ACK or NACK
01210         if (*sda_in) {
01211             return -1;//NACK - write failed
01212         }
01213         wait_ns(2500);
01214         *scl_val = 0;
01215         wait_ns(2500);
01216     }
01217 
01218     //start condition
01219     *sda_val = 1;
01220     *scl_val = 1;
01221     wait_ns(2500);
01222     *sda_val = 0;
01223     wait_ns(2500);
01224 
01225     // begin reading data, write (dev_addr | 1) first
01226     dev_addr |= 1;
01227     for (int j = -1; j < length; j += 1) {
01228         uint8_t read_byte = 0;
01229         for (int i = 7; i > -1; i -= 1) {
01230             if (j == -1) {
01231                 *scl_val = 0;
01232                 *sda_val = 0;
01233                 send_bit = (dev_addr & (1 << i)) >> i;
01234                 *sda_val = send_bit;
01235                 wait_ns(500);
01236 
01237                 *scl_val = 1;
01238                 wait_ns(2500);
01239                 *scl_val = 0;
01240                 wait_ns(1000);
01241                 *sda_val = 0;
01242                 wait_ns(1000);
01243             } else {
01244                 *scl_val = 1;
01245                 read_byte |= (*sda_in << i);
01246                 wait_ns(2500);
01247                 *scl_val = 0;
01248                 wait_ns(2500);
01249             }
01250         }
01251         if (j > -1) {
01252             data[j] = read_byte;
01253         }
01254         if (j == -1) {
01255             // receive ACK from IO extender
01256             *sda_val = 1;//make sda high z to receive ACK
01257             //clk the ACK
01258             *scl_val = 1;
01259             //read sda to check for ACK or NACK
01260             if (*sda_in) {
01261                 return -1;//NACK - write failed
01262             }
01263             wait_ns(2500);
01264             *scl_val = 0;
01265             wait_ns(2500);
01266         } else {
01267             if (j == (length - 1)) { //NACK to signal end of read
01268                 *sda_val = 1;
01269                 wait_ns(1000);
01270                 *scl_val = 1;
01271                 wait_ns(2500);
01272                 *scl_val = 0;
01273                 wait_ns(1500);
01274             } else {//ACK to signal read will continue
01275                 *sda_val = 0;
01276                 wait_ns(1000);
01277                 *scl_val = 1;
01278                 wait_ns(2500);
01279                 *scl_val = 0;
01280                 wait_ns(500);
01281                 *sda_val = 1;
01282                 wait_ns(1000);
01283             }
01284         }
01285     }
01286 
01287     //stop condition
01288     *sda_val = 0;
01289     wait_ns(2500);
01290     *scl_val = 1;
01291     wait_ns(2500);
01292     *sda_val = 1;
01293     wait_ns(2500);
01294 
01295     sys_pin_mode_disabled();
01296 
01297     return 0;
01298 }
01299 
01300 int MbedTester::io_expander_i2c_write(uint8_t i2c_index, uint8_t dev_addr, uint8_t *data, int length)
01301 {
01302     _update_control_pins();
01303     //sda_in = _miso_index
01304     //sda_val = _aux_index
01305     //scl_in = _mosi_index (PHYSICAL_NC)
01306     //scl_val = _clk_index
01307     mbed::DigitalInOut *sda_in = _miso;
01308     mbed::DigitalInOut *sda_val = _aux;
01309     mbed::DigitalInOut *scl_val = _clk;
01310     sda_in->input();
01311     sda_val->output();
01312     *sda_val = 1;
01313     scl_val->output();
01314     sys_pin_mode_i2c_io_expander(i2c_index, _miso_index, _aux_index, PHYSICAL_NC, _clk_index);
01315 
01316     //start condition
01317     *scl_val = 1;
01318     wait_ns(2500);
01319     *sda_val = 0;
01320     wait_ns(2500);
01321 
01322     // begin writing data, dev_addr first
01323     uint8_t send_bit;
01324     for (int j = -1; j < length; j += 1) {
01325         *scl_val = 0;
01326         *sda_val = 0;
01327         for (int i = 7; i > -1; i -= 1) {
01328             if (j == -1) {
01329                 send_bit = (dev_addr & (1 << i)) >> i;
01330             } else {
01331                 send_bit = (data[j] & (1 << i)) >> i;
01332             }
01333 
01334             *sda_val = send_bit;
01335             wait_ns(500);
01336 
01337             *scl_val = 1;
01338             wait_ns(2500);
01339             *scl_val = 0;
01340             wait_ns(1000);
01341             *sda_val = 0;
01342             wait_ns(1000);
01343         }
01344         // receive ACK from IO extender
01345         *sda_val = 1;//make sda high z to receive ACK
01346         //clk the ACK
01347         *scl_val = 1;
01348         //read sda to check for ACK or NACK
01349         if (*sda_in) {
01350             return -1;//NACK - write failed
01351         }
01352         wait_ns(2500);
01353         *scl_val = 0;
01354         wait_ns(2500);
01355     }
01356 
01357     //stop condition
01358     *sda_val = 0;
01359     wait_ns(2500);
01360     *scl_val = 1;
01361     wait_ns(2500);
01362     *sda_val = 1;
01363     wait_ns(2500);
01364 
01365     sys_pin_mode_disabled();
01366 
01367     return 0;
01368 }
01369 
01370 int MbedTester::pin_set_pull_bb(PinName pin, PullMode mode)
01371 {
01372     int index = _form_factor.index(pin);
01373     if ((index < 0) || (index > 127)) {
01374         error("Pin %i not in form factor", pin);
01375         return -1;
01376     }
01377     uint8_t chip_num;//can be 0-5
01378     SystemPin sda;//can be I2CSda0, I2CSda1, or I2CSda2
01379     SystemPin scl;//can be I2CScl0, I2CScl1, or I2CScl2
01380     uint16_t dev_addr;//can be 0x44 or 0x46
01381     uint8_t port_num;//can be 0-23
01382     uint8_t output_port_reg;//can be 4, 5, or 6
01383     uint8_t config_reg;//can be 12, 13, or 14
01384     uint8_t reg_bit;//can be 0-7
01385     uint8_t cmd0[2];//for writing configuration register
01386     uint8_t cmd1[2];//for writing output port register
01387 
01388     chip_num = index / 24;
01389     if ((chip_num == 0) || (chip_num == 1)) {
01390         sda = I2CSda0;
01391         scl = I2CScl0;
01392     } else if ((chip_num == 2) || (chip_num == 3)) {
01393         sda = I2CSda1;
01394         scl = I2CScl1;
01395     } else if ((chip_num == 4) || (chip_num == 5)) {
01396         sda = I2CSda2;
01397         scl = I2CScl2;
01398     } else {
01399         error("Pin %i not in form factor", pin);
01400         return -1;
01401     }
01402     dev_addr = (chip_num % 2) ? 0x44 : 0x46;
01403     port_num = index % 24;
01404     output_port_reg = 4 + (port_num / 8);
01405     config_reg = 12 + (port_num / 8);
01406     reg_bit = port_num % 8;
01407 
01408     uint8_t read_config_byte[1];
01409     uint8_t read_output_byte[1];
01410     if (io_expander_i2c_read_bb(sda, scl, dev_addr, config_reg, read_config_byte, 1) != 0) {
01411         return -1;
01412     }
01413     if (io_expander_i2c_read_bb(sda, scl, dev_addr, output_port_reg, read_output_byte, 1) != 0) {
01414         return -1;
01415     }
01416     cmd0[0] = config_reg;
01417     if ((mode == PullDown) || (mode == PullUp)) {
01418         cmd0[1] = read_config_byte[0] & ~(1 << reg_bit);
01419         cmd1[0] = output_port_reg;
01420         if (mode == PullDown) {
01421             cmd1[1] = read_output_byte[0] & ~(1 << reg_bit);
01422         } else if (mode == PullUp) {
01423             cmd1[1] = read_output_byte[0] | (1 << reg_bit);
01424         }
01425     } else if (mode == PullNone) {
01426         cmd0[1] = read_config_byte[0] | (1 << reg_bit);
01427     }
01428 
01429     //write configuration register for all 3 modes
01430     if (io_expander_i2c_write_bb(sda, scl, dev_addr, cmd0, 2) != 0) {
01431         return -1;
01432     }
01433     //only write output register for pulldown and pullup
01434     if ((mode == PullDown) || (mode == PullUp)) {
01435         if (io_expander_i2c_write_bb(sda, scl, dev_addr, cmd1, 2) != 0) {
01436             return -1;
01437         }
01438     }
01439     return 0;
01440 }
01441 
01442 uint8_t MbedTester::io_expander_read_bb(PinName pin, IOExpanderReg reg_type)
01443 {
01444     int index = _form_factor.index(pin);
01445     uint8_t read_byte[1] = {0};
01446     uint8_t chip_num;//can be 0-5
01447     SystemPin sda;//can be I2CSda0, I2CSda1, or I2CSda2
01448     SystemPin scl;//can be I2CScl0, I2CScl1, or I2CScl2
01449     uint16_t dev_addr;//can be 0x44 or 0x46
01450     uint8_t port_num;//can be 0-23
01451     uint8_t input_port_reg;//can be 0, 1, or 2
01452     uint8_t output_port_reg;//can be 4, 5, or 6
01453     uint8_t config_reg;//can be 12, 13, or 14
01454     uint8_t reg_bit;//can be 0-7
01455 
01456     chip_num = index / 24;
01457     if ((chip_num == 0) || (chip_num == 1)) {
01458         sda = I2CSda0;
01459         scl = I2CScl0;
01460     } else if ((chip_num == 2) || (chip_num == 3)) {
01461         sda = I2CSda1;
01462         scl = I2CScl1;
01463     } else if ((chip_num == 4) || (chip_num == 5)) {
01464         sda = I2CSda2;
01465         scl = I2CScl2;
01466     } else {
01467         sda = (SystemPin) - 1;
01468         scl = (SystemPin) - 1;
01469         error("Invalid pin index, index should be in the range of 0-127");
01470     }
01471 
01472     dev_addr = (chip_num % 2) ? 0x44 : 0x46;
01473     port_num = index % 24;
01474     input_port_reg = (port_num / 8);
01475     output_port_reg = 4 + (port_num / 8);
01476     config_reg = 12 + (port_num / 8);
01477     reg_bit = port_num % 8;
01478     uint8_t reg;
01479     if (reg_type == RegInput) {
01480         reg = input_port_reg;
01481     } else if (reg_type == RegOutput) {
01482         reg = output_port_reg;
01483     } else if (reg_type == RegConfig) {
01484         reg = config_reg;
01485     } else {
01486         reg = 0xFF;
01487         error("Invalid register type, should be: INPUT, OUTPUT, or CONFIG");
01488     }
01489 
01490     int read_success = io_expander_i2c_read_bb(sda, scl, dev_addr, reg, read_byte, 1);
01491     MBED_ASSERT(read_success == 0);
01492     uint8_t bit = (read_byte[0] & (1 << reg_bit)) >> reg_bit;
01493     return bit;
01494 }
01495 
01496 int MbedTester::io_expander_i2c_read_bb(SystemPin sda, SystemPin scl, uint8_t dev_addr, uint8_t start_reg, uint8_t *data, int length)
01497 {
01498     //start condition
01499     sys_pin_write(sda, 0, false);
01500     sys_pin_write(scl, 0, false);
01501     sys_pin_write(sda, 0, true);
01502 
01503     // begin writing data, dev_addr first
01504     uint8_t send_bit;
01505     for (int j = 0; j < 2; j += 1) {
01506         sys_pin_write(scl, 0, true);
01507         sys_pin_write(sda, 0, true);
01508         for (int i = 7; i > -1; i -= 1) {
01509             if (j == 0) {
01510                 send_bit = (dev_addr & (1 << i)) >> i;
01511             } else {
01512                 send_bit = (start_reg & (1 << i)) >> i;
01513             }
01514             if (send_bit == 1) {
01515                 sys_pin_write(sda, 0, false);
01516             } else if (send_bit == 0) {
01517                 sys_pin_write(sda, 0, true);
01518             }
01519             sys_pin_write(scl, 0, false);
01520             sys_pin_write(scl, 0, true);
01521             sys_pin_write(sda, 0, true);
01522         }
01523         // receive ACK from IO extender
01524         sys_pin_write(sda, 0, false);//make sda high z to receive ACK
01525         //clk the ACK
01526         sys_pin_write(scl, 0, false);
01527         //read sda to check for ACK or NACK
01528         if (sys_pin_read(sda)) {
01529             return -1;//NACK - write failed
01530         }
01531         sys_pin_write(scl, 0, true);
01532     }
01533 
01534     //start condition
01535     sys_pin_write(sda, 0, false);
01536     sys_pin_write(scl, 0, false);
01537     sys_pin_write(sda, 0, true);
01538 
01539     // begin reading data, write (dev_addr | 1) first
01540     dev_addr |= 1;
01541     for (int j = -1; j < length; j += 1) {
01542         uint8_t read_byte = 0;
01543         for (int i = 7; i > -1; i -= 1) {
01544             if (j == -1) {
01545                 sys_pin_write(scl, 0, true);
01546                 sys_pin_write(sda, 0, true);
01547                 send_bit = (dev_addr & (1 << i)) >> i;
01548                 if (send_bit == 1) {
01549                     sys_pin_write(sda, 0, false);
01550                 } else if (send_bit == 0) {
01551                     sys_pin_write(sda, 0, true);
01552                 }
01553                 sys_pin_write(scl, 0, false);
01554                 sys_pin_write(scl, 0, true);
01555                 sys_pin_write(sda, 0, true);
01556             } else {
01557                 sys_pin_write(scl, 0, false);
01558                 read_byte |= (sys_pin_read(sda) << i);
01559                 sys_pin_write(scl, 0, true);
01560             }
01561         }
01562         if (j > -1) {
01563             data[j] = read_byte;
01564         }
01565         if (j == -1) {
01566             // receive ACK from IO extender
01567             sys_pin_write(sda, 0, false);//make sda high z to receive ACK
01568             //clk the ACK
01569             sys_pin_write(scl, 0, false);
01570             //read sda to check for ACK or NACK
01571             if (sys_pin_read(sda)) {
01572                 return -1;//NACK - write failed
01573             }
01574             sys_pin_write(scl, 0, true);
01575         } else {
01576             if (j == (length - 1)) { //NACK to signal end of read
01577                 sys_pin_write(sda, 0, false);
01578                 sys_pin_write(scl, 0, false);
01579                 sys_pin_write(scl, 0, true);
01580             } else {//ACK to signal read will continue
01581                 sys_pin_write(sda, 0, true);
01582                 sys_pin_write(scl, 0, false);
01583                 sys_pin_write(scl, 0, true);
01584                 sys_pin_write(sda, 0, false);
01585             }
01586         }
01587     }
01588 
01589     //stop condition
01590     sys_pin_write(sda, 0, true);
01591     sys_pin_write(scl, 0, false);
01592     sys_pin_write(sda, 0, false);
01593     return 0;
01594 }
01595 
01596 int MbedTester::io_expander_i2c_write_bb(SystemPin sda, SystemPin scl, uint8_t dev_addr, uint8_t *data, int length)
01597 {
01598     //start condition
01599     sys_pin_write(sda, 0, false);
01600     sys_pin_write(scl, 0, false);
01601     sys_pin_write(sda, 0, true);
01602 
01603     // begin writing data, dev_addr first
01604     uint8_t send_bit;
01605     for (int j = -1; j < length; j += 1) {
01606         sys_pin_write(scl, 0, true);
01607         sys_pin_write(sda, 0, true);
01608         for (int i = 7; i > -1; i -= 1) {
01609             if (j == -1) {
01610                 send_bit = (dev_addr & (1 << i)) >> i;
01611             } else {
01612                 send_bit = (data[j] & (1 << i)) >> i;
01613             }
01614             if (send_bit == 1) {
01615                 sys_pin_write(sda, 0, false);
01616             } else if (send_bit == 0) {
01617                 sys_pin_write(sda, 0, true);
01618             }
01619             sys_pin_write(scl, 0, false);
01620             sys_pin_write(scl, 0, true);
01621             sys_pin_write(sda, 0, true);
01622         }
01623         // receive ACK from IO extender
01624         sys_pin_write(sda, 0, false);//make sda high z to receive ACK
01625         //clk the ACK
01626         sys_pin_write(scl, 0, false);
01627         //read sda to check for ACK or NACK
01628         if (sys_pin_read(sda)) {
01629             return -1;//NACK - write failed
01630         }
01631         sys_pin_write(scl, 0, true);
01632     }
01633 
01634     //stop condition
01635     sys_pin_write(sda, 0, true);
01636     sys_pin_write(scl, 0, false);
01637     sys_pin_write(sda, 0, false);
01638     return 0;
01639 }
01640 
01641 void MbedTester::set_analog_out(bool enable, float voltage)
01642 {
01643     uint32_t cycles_high = (int)(100 * voltage);
01644     uint32_t period = 100;
01645     set_pwm_period_and_cycles_high(period, cycles_high);
01646     set_pwm_enable(enable);
01647 }
01648 
01649 int MbedTester::set_mux_addr(PinName pin)
01650 {
01651     int index = _form_factor.index(pin);
01652     if ((index < 0) || (index > 127)) {
01653         error("Pin %i not in form factor", pin);
01654         return -1;
01655     }
01656 
01657     return set_mux_addr_index(index);
01658 }
01659 
01660 int MbedTester::set_mux_addr_index(int index)
01661 {
01662     sys_pin_write(AnalogMuxAddr0, index & 0x01, true);
01663     sys_pin_write(AnalogMuxAddr1, (index & 0x02) >> 1, true);
01664     sys_pin_write(AnalogMuxAddr2, (index & 0x04) >> 2, true);
01665     sys_pin_write(AnalogMuxAddr3, (index & 0x08) >> 3, true);
01666     sys_pin_write(AnalogMuxAddr4, (index & 0x10) >> 4, true);
01667     sys_pin_write(AnalogMuxAddr5, (index & 0x20) >> 5, true);
01668     sys_pin_write(AnalogMuxAddr6, (index & 0x40) >> 6, true);
01669     sys_pin_write(AnalogMuxAddr7, (index & 0x80) >> 7, true);
01670 
01671     return 0;
01672 }
01673 
01674 void MbedTester::set_mux_enable(bool val)
01675 {
01676     if (val == true) {
01677         sys_pin_write(AnalogMuxEnable, 0, true);//enable analog MUXes
01678     } else if (val == false) {
01679         sys_pin_write(AnalogMuxEnable, 1, true);//disable analog MUXes
01680     }
01681     wait_us(10);
01682 }
01683 
01684 void MbedTester::set_pwm_enable(bool val)
01685 {
01686     uint8_t data;
01687     if (val == true) {
01688         data = 1;
01689     } else if (val == false) {
01690         data = 0;
01691     }
01692     write(TESTER_SYS_IO_PWM_ENABLE, &data, sizeof(data));
01693 }
01694 
01695 bool MbedTester::get_pwm_enable()
01696 {
01697     uint8_t val = 0;
01698     read(TESTER_SYS_IO_PWM_ENABLE, &val, sizeof(val));
01699     if (val == 1) {
01700         return true;
01701     } else if (val == 0) {
01702         return false;
01703     } else {
01704         error("Corrupt pwm enable value");
01705         return false;
01706     }
01707 }
01708 
01709 void MbedTester::set_pwm_period_and_cycles_high(uint32_t period, uint32_t cycles_high)
01710 {
01711     set_pwm_enable(false);
01712     uint32_t p = period - 1;//period in cycles
01713     uint32_t d = cycles_high;//number of cycles pwm out is high
01714     write(TESTER_SYS_IO_PWM_PERIOD, (uint8_t *)&p, sizeof(p));
01715     write(TESTER_SYS_IO_PWM_CYCLES_HIGH, (uint8_t *)&d, sizeof(d));
01716     set_pwm_enable(true);
01717 }
01718 
01719 uint32_t MbedTester::get_pwm_period()
01720 {
01721     uint32_t period = 0;
01722     read(TESTER_SYS_IO_PWM_PERIOD, (uint8_t *)&period, sizeof(period));
01723     return period + 1;//clk cycles
01724 }
01725 
01726 uint8_t MbedTester::get_pwm_cycles_high()
01727 {
01728     uint8_t cycles_high = 0;
01729     read(TESTER_SYS_IO_PWM_CYCLES_HIGH, &cycles_high, sizeof(cycles_high));
01730     return cycles_high;
01731 }
01732 
01733 uint16_t MbedTester::get_analogmuxin_measurement()
01734 {
01735     rtos::ThisThread::sleep_for(1);//wait for value to stabalize
01736     //take snapshot of conversion value to make safe for reading
01737     set_snapshot();
01738     uint16_t an_mux_analogin_measurement = 0;
01739     read(TESTER_SYS_IO_AN_MUX_ANALOGIN_MEASUREMENT, (uint8_t *)&an_mux_analogin_measurement, sizeof(an_mux_analogin_measurement));
01740     return an_mux_analogin_measurement;
01741 }
01742 
01743 uint16_t MbedTester::get_anin_measurement(int index)
01744 {
01745     //check index is in bounds
01746     if ((index < 0) || (index >= ANALOG_COUNT)) {
01747         error("AnalogIn index is out of bounds");
01748     }
01749     //take snapshot of conversion value to make safe for reading
01750     set_snapshot();
01751     uint16_t anin_measurement = 0;
01752     read((TESTER_SYS_IO_ANIN0_MEASUREMENT + (index * 10)), (uint8_t *)&anin_measurement, sizeof(anin_measurement)); //10 because sizeof measurement + sizeof measurements_sum = 10
01753     return anin_measurement;
01754 }
01755 
01756 void MbedTester::get_anin_sum_samples_cycles(int index, uint64_t *sum, uint32_t *samples, uint64_t *cycles)
01757 {
01758     //check index is in bounds
01759     if ((index < 0) || (index >= ANALOG_COUNT)) {
01760         error("AnalogIn index is out of bounds");
01761     }
01762     //take snapshot of the sum/samples/cycles so that all 3 values are correct in relation to each other
01763     set_snapshot();
01764     read((TESTER_SYS_IO_ANIN0_MEASUREMENTS_SUM + (index * 10)), (uint8_t *)sum, sizeof(*sum)); //10 because sizeof measurement + sizeof measurements_sum = 10
01765     read(TESTER_SYS_IO_NUM_POWER_SAMPLES, (uint8_t *)samples, sizeof(*samples));
01766     read(TESTER_SYS_IO_NUM_POWER_CYCLES, (uint8_t *)cycles, sizeof(*cycles));
01767 }
01768 
01769 void MbedTester::set_snapshot()
01770 {
01771     uint8_t data = 1;
01772     write(TESTER_SYS_IO_ADC_SNAPSHOT, &data, sizeof(data));
01773     wait_us(1);
01774 }
01775 
01776 void MbedTester::set_sample_adc(bool val)
01777 {
01778     uint8_t data;
01779     if (val == true) {
01780         data = 1;
01781     } else if (val == false) {
01782         data = 0;
01783     }
01784     write(TESTER_SYS_IO_SAMPLE_ADC, &data, sizeof(data));
01785 }
01786 
01787 float MbedTester::get_analog_in()
01788 {
01789     uint16_t data = get_analogmuxin_measurement();
01790     float data_f = (float)data / 4095.0f;
01791     return data_f;
01792 }
01793 
01794 float MbedTester::get_anin_voltage(int index)
01795 {
01796     uint16_t data = get_anin_measurement(index);
01797     float data_f = (float)data / 4095.0f;
01798     return data_f;
01799 }
01800 
01801 int MbedTester::gpio_read(LogicalPin gpio)
01802 {
01803     if (gpio >= LogicalPinCount) {
01804         error("Invalid pin for gpio_read");
01805         return 0;
01806     }
01807     uint8_t data = 0;
01808     read(TESTER_GPIO + gpio, &data, sizeof(data));
01809     return data;
01810 }
01811 
01812 void MbedTester::gpio_write(LogicalPin gpio, int value, bool drive)
01813 {
01814     if (gpio >= LogicalPinCount) {
01815         error("Invalid pin for gpio_write");
01816         return;
01817     }
01818     uint8_t data = 0;
01819     data |= value ? (1 << 0) : 0;
01820     data |= drive ? (1 << 1) : 0;
01821     write(TESTER_GPIO + gpio, &data, sizeof(data));
01822 }
01823 
01824 void MbedTester::io_metrics_start()
01825 {
01826     uint8_t data = TESTER_IO_METRICS_CTRL_RESET_BIT;
01827     write(TESTER_IO_METRICS_CTRL, &data, sizeof(data));
01828 
01829     data = TESTER_IO_METRICS_CTRL_ACTIVE_BIT;
01830     write(TESTER_IO_METRICS_CTRL, &data, sizeof(data));
01831 }
01832 
01833 void MbedTester::io_metrics_stop()
01834 {
01835     uint8_t data = 0;
01836     write(TESTER_IO_METRICS_CTRL, &data, sizeof(data));
01837 }
01838 
01839 void MbedTester::io_metrics_continue()
01840 {
01841     uint8_t data = TESTER_IO_METRICS_CTRL_ACTIVE_BIT;
01842     write(TESTER_IO_METRICS_CTRL, &data, sizeof(data));
01843 }
01844 
01845 uint32_t MbedTester::io_metrics_min_pulse_low(LogicalPin pin)
01846 {
01847     if (pin >= LogicalPinCount) {
01848         error("Invalid pin for io_metrics");
01849         return 0;
01850     }
01851 
01852     uint32_t data = 0;
01853     read(TESTER_IO_METRICS_MIN_PULSE_LOW(pin), (uint8_t *)&data, sizeof(data));
01854     return data;
01855 }
01856 
01857 uint32_t MbedTester::io_metrics_min_pulse_high(LogicalPin pin)
01858 {
01859     if (pin >= LogicalPinCount) {
01860         error("Invalid pin for io_metrics");
01861         return 0;
01862     }
01863 
01864     uint32_t data = 0;
01865     read(TESTER_IO_METRICS_MIN_PULSE_HIGH(pin), (uint8_t *)&data, sizeof(data));
01866     return data;
01867 }
01868 
01869 uint32_t MbedTester::io_metrics_max_pulse_low(LogicalPin pin)
01870 {
01871     if (pin >= LogicalPinCount) {
01872         error("Invalid pin for io_metrics");
01873         return 0;
01874     }
01875 
01876     uint32_t data = 0;
01877     read(TESTER_IO_METRICS_MAX_PULSE_LOW(pin), (uint8_t *)&data, sizeof(data));
01878     return data;
01879 }
01880 
01881 uint32_t MbedTester::io_metrics_max_pulse_high(LogicalPin pin)
01882 {
01883     if (pin >= LogicalPinCount) {
01884         error("Invalid pin for io_metrics");
01885         return 0;
01886     }
01887 
01888     uint32_t data = 0;
01889     read(TESTER_IO_METRICS_MAX_PULSE_HIGH(pin), (uint8_t *)&data, sizeof(data));
01890     return data;
01891 }
01892 
01893 uint32_t MbedTester::io_metrics_rising_edges(LogicalPin pin)
01894 {
01895     if (pin >= LogicalPinCount) {
01896         error("Invalid pin for io_metrics");
01897         return 0;
01898     }
01899 
01900     uint32_t data = 0;
01901     read(TESTER_IO_METRICS_RISING_EDGES(pin), (uint8_t *)&data, sizeof(data));
01902     return data;
01903 }
01904 
01905 uint32_t MbedTester::io_metrics_falling_edges(LogicalPin pin)
01906 {
01907     if (pin >= LogicalPinCount) {
01908         error("Invalid pin for io_metrics");
01909         return 0;
01910     }
01911 
01912     uint32_t data = 0;
01913     read(TESTER_IO_METRICS_FALLING_EDGES(pin), (uint8_t *)&data, sizeof(data));
01914     return data;
01915 }
01916 
01917 bool MbedTester::sys_pin_read(SystemPin pin)
01918 {
01919 
01920     if (pin >= SystemPinCount) {
01921         error("Invalid pin for gpio_read");
01922         return 0;
01923     }
01924     uint8_t data = 0;
01925     read(TESTER_SYS_IO + pin, &data, sizeof(data));
01926     return data;
01927 }
01928 
01929 void MbedTester::sys_pin_write(SystemPin pin, int value, bool drive)
01930 {
01931     if (pin >= SystemPinCount) {
01932         error("Invalid pin for gpio_write");
01933         return;
01934     }
01935     uint8_t data = 0;
01936     data |= value ? (1 << 0) : 0;
01937     data |= drive ? (1 << 1) : 0;
01938     write(TESTER_SYS_IO + pin, &data, sizeof(data));
01939 }
01940 
01941 void MbedTester::sys_pin_mode_disabled()
01942 {
01943     const uint32_t base = LogicalPinTotal;
01944 
01945     pin_map_index(PHYSICAL_NC, (LogicalPin)(base + 0));
01946     pin_map_index(PHYSICAL_NC, (LogicalPin)(base + 1));
01947     pin_map_index(PHYSICAL_NC, (LogicalPin)(base + 2));
01948     pin_map_index(PHYSICAL_NC, (LogicalPin)(base + 3));
01949 
01950     uint8_t mode = TESTER_SYS_IO_MODE_DISABLED;
01951     write(TESTER_SYS_IO_MODE, &mode, sizeof(mode));
01952 }
01953 
01954 void MbedTester::sys_pin_mode_spi_serial_flash(PhysicalIndex mosi, PhysicalIndex miso, PhysicalIndex clk, PhysicalIndex ssel)
01955 {
01956     const uint32_t base = LogicalPinTotal;
01957 
01958     pin_map_index(mosi, (LogicalPin)(base + 0));
01959     pin_map_index(miso, (LogicalPin)(base + 1));
01960     pin_map_index(clk, (LogicalPin)(base + 2));
01961     pin_map_index(ssel, (LogicalPin)(base + 3));
01962 
01963     uint8_t mode = TESTER_SYS_IO_MODE_SPI_SERIAL_FLASH;
01964     write(TESTER_SYS_IO_MODE, &mode, sizeof(mode));
01965 }
01966 
01967 void MbedTester::sys_pin_mode_i2c_io_expander(int index, PhysicalIndex sda_in, PhysicalIndex sda_val, PhysicalIndex scl_in, PhysicalIndex scl_val)
01968 {
01969     const uint32_t base = LogicalPinTotal;
01970 
01971     pin_map_index(sda_in, (LogicalPin)(base + 0));
01972     pin_map_index(sda_val, (LogicalPin)(base + 1));
01973     pin_map_index(scl_in, (LogicalPin)(base + 2));
01974     pin_map_index(scl_val, (LogicalPin)(base + 3));
01975 
01976     uint8_t mode = 0;
01977     if (index == 0) {
01978         mode = TESTER_SYS_IO_MODE_I2C_IO_EXPANDER0;
01979     } else if (index == 1) {
01980         mode = TESTER_SYS_IO_MODE_I2C_IO_EXPANDER1;
01981     } else if (index == 2) {
01982         mode = TESTER_SYS_IO_MODE_I2C_IO_EXPANDER2;
01983     } else {
01984         error("Invalid index for sys_pin_mode_i2c_io_expander");
01985     }
01986 
01987     write(TESTER_SYS_IO_MODE, &mode, sizeof(mode));
01988 }
01989 
01990 void MbedTester::pin_map_index(PhysicalIndex physical_index, LogicalPin logical)
01991 {
01992     uint8_t remap;
01993     if ((physical_index >= PHYSICAL_PINS) && (physical_index != PHYSICAL_NC)) {
01994         error("Invalid physical pin index %i", physical_index);
01995         return;
01996     }
01997     if (logical >= sizeof(_mapping) / sizeof(_mapping[0])) {
01998         error("Invalid logical pin %i", logical);
01999         return;
02000     }
02001 
02002     // Unmap the previous pin if it had been mapped
02003     if (_mapping[logical] < PHYSICAL_PINS) {
02004         remap = PHYSICAL_NC;
02005         write(TESTER_REMAP + _mapping[logical], &remap, sizeof(remap));
02006     }
02007     _mapping[logical] = physical_index;
02008 
02009     // Remap physical pin if it is not PHYSICAL_NC
02010     if (physical_index < PHYSICAL_PINS) {
02011         remap = logical;
02012         write(TESTER_REMAP + physical_index, &remap, sizeof(remap));
02013     }
02014     // Remap logical pin
02015     remap = physical_index;
02016     write(TESTER_REMAP + PHYSICAL_PINS + logical, &remap, sizeof(remap));
02017 }
02018 
02019 void MbedTester::write(uint32_t addr, const uint8_t *data, uint32_t size)
02020 {
02021     _update_control_pins();
02022 
02023     mbed_tester_command(_clk, _mosi, _miso, _miso_index, addr, true, (uint8_t *)data, size);
02024 }
02025 
02026 void MbedTester::read(uint32_t addr, uint8_t *data, uint32_t size)
02027 {
02028     _update_control_pins();
02029 
02030     mbed_tester_command(_clk, _mosi, _miso, _miso_index, addr, false, data, size);
02031 }
02032 
02033 bool MbedTester::self_test_all()
02034 {
02035     return self_test_control_channels() && self_test_control_miso();
02036 }
02037 
02038 bool MbedTester::self_test_control_channels()
02039 {
02040     for (uint32_t i = 0; i < _form_factor.count() / 2; i++) {
02041         const int clk_index = i * 2 + 0;
02042         const int mosi_index = i * 2 + 1;
02043         const PinName clk = _form_factor.get(clk_index);
02044         const PinName mosi = _form_factor.get(mosi_index);
02045 
02046         // Check if the control pair is allowed and skip if it is not
02047         if (_exclude_pins.has_pin(clk) || _exclude_pins.has_pin(mosi)) {
02048             mbed_tester_printf("Skipping pin indexes clk=%i, mosi=%i\r\n", i * 2 + 0, i * 2 + 1);
02049             continue;
02050         }
02051 
02052         // Find a pin to use as miso
02053         int miso_index = 0;
02054         PinName miso = NC;
02055         DynamicPinList more_restricted(_exclude_pins);
02056         more_restricted.add(clk);
02057         more_restricted.add(mosi);
02058         for (uint32_t j = 0; j < _form_factor.count(); j++) {
02059             miso_index = j;
02060             const PinName temp = _form_factor.get(miso_index);
02061             if (!more_restricted.has_pin(temp)) {
02062                 miso = temp;
02063                 break;
02064             }
02065         }
02066         if (miso == NC) {
02067             set_control_pins_auto();
02068             return false;
02069         }
02070 
02071         // Find a pin to use as aux
02072         int aux_index = 0;
02073         PinName aux = NC;
02074         more_restricted.add(miso);
02075         for (uint32_t j = 0; j < _form_factor.count(); j++) {
02076             aux_index = j;
02077             const PinName temp = _form_factor.get(aux_index);
02078             if (!more_restricted.has_pin(temp)) {
02079                 aux = temp;
02080                 break;
02081             }
02082         }
02083         if (aux == NC) {
02084             set_control_pins_auto();
02085             return false;
02086         }
02087 
02088         // Write and read back a value
02089         mbed_tester_printf("Testing clk_index=%2i, mosi_index=%2i, miso_index=%2i, aux_index=%2i\r\n", clk_index, mosi_index, miso_index, aux_index);
02090         set_control_pins_manual(clk, mosi, miso, aux);
02091         if (!self_test_control_current()) {
02092             mbed_tester_printf("  Fail\r\n");
02093             set_control_pins_auto();
02094             return false;
02095         }
02096         mbed_tester_printf("  Pass\r\n");
02097     }
02098 
02099     set_control_pins_auto();
02100     return true;
02101 }
02102 
02103 bool MbedTester::self_test_control_miso()
02104 {
02105     for (uint32_t i = 0; i < _form_factor.count(); i++) {
02106         const int miso_index = i;
02107         const PinName miso = _form_factor.get(miso_index);
02108 
02109         if (_exclude_pins.has_pin(miso)) {
02110             mbed_tester_printf("Skipping miso index %i\r\n", i);
02111             continue;
02112         }
02113 
02114         // Find pins to use as clk and mosi
02115         int clk_index = 0;
02116         int mosi_index = 0;
02117         PinName clk = NC;
02118         PinName mosi = NC;
02119         DynamicPinList more_restricted(_exclude_pins);
02120         more_restricted.add(miso);
02121         for (uint32_t j = 0; j < _form_factor.count() / 2; j++) {
02122             clk_index = j * 2 + 0;
02123             mosi_index = j * 2 + 1;
02124             const PinName possible_clk = _form_factor.get(clk_index);
02125             const PinName possible_mosi = _form_factor.get(mosi_index);
02126 
02127             // Check if the control pair is allowed and skip if it is not
02128             if (!more_restricted.has_pin(possible_clk) && !more_restricted.has_pin(possible_mosi)) {
02129                 clk = possible_clk;
02130                 mosi = possible_mosi;
02131                 break;
02132             }
02133         }
02134 
02135         if ((clk == NC) && (mosi == NC)) {
02136             set_control_pins_auto();
02137             return false;
02138         }
02139 
02140         // Find aux pin
02141         int aux_index = 0;
02142         PinName aux = NC;
02143         more_restricted.add(clk);
02144         more_restricted.add(mosi);
02145         for (uint32_t j = 0; j < _form_factor.count(); j++) {
02146             aux_index = j;
02147             const PinName possible_aux = _form_factor.get(aux_index);
02148 
02149             // Check if the control pair is allowed and skip if it is not
02150             if (!more_restricted.has_pin(possible_aux)) {
02151                 aux = possible_aux;
02152                 break;
02153             }
02154         }
02155         if (aux == NC) {
02156             set_control_pins_auto();
02157             return false;
02158         }
02159 
02160 
02161         mbed_tester_printf("Testing clk_index=%2i, mosi_index=%2i, miso_index=%2i, aux_index=%2i\r\n", clk_index, mosi_index, miso_index, aux_index);
02162         set_control_pins_manual(clk, mosi, miso, aux);
02163         if (!self_test_control_current()) {
02164             mbed_tester_printf("  Fail\r\n");
02165             set_control_pins_auto();
02166             return false;
02167         }
02168         mbed_tester_printf("  Pass\r\n");
02169     }
02170     set_control_pins_auto();
02171     return true;
02172 }
02173 
02174 bool MbedTester::self_test_control_current()
02175 {
02176     uint8_t buf[4];
02177 
02178     read(TESTER_CONTROL, buf, sizeof(buf));
02179 
02180     return memcmp(buf, "mbed", sizeof(buf)) == 0;
02181 }
02182 
02183 bool MbedTester::_find_control_indexes(PhysicalIndex &clk_out, PhysicalIndex &mosi_out, PhysicalIndex &miso_out, PhysicalIndex &aux_out)
02184 {
02185     MbedTesterBitMap<PHYSICAL_PINS> allowed;
02186     const size_t max_pins = _form_factor.count();
02187     const size_t max_controls = max_pins / 2;
02188 
02189     for (size_t i = 0; i < max_pins; i++) {
02190         PinName pin = _form_factor.get(i);
02191         if ((pin == NC) || _exclude_pins.has_pin(pin)) {
02192             // Skip these pins
02193             continue;
02194         }
02195 
02196         // Pin is allowed
02197         allowed.set(i);
02198     }
02199     for (size_t i = 0; i < LogicalPinTotal; i++) {
02200         PhysicalIndex index = _mapping[i];
02201         if (index < PHYSICAL_PINS) {
02202             allowed.clear(index);
02203         }
02204     }
02205 
02206     for (size_t i = 0; i < max_controls; i++) {
02207         uint8_t clk_index = i * 2 + 0;
02208         uint8_t mosi_index = i * 2 + 1;
02209         if (!allowed.get(clk_index) || !allowed.get(mosi_index)) {
02210             continue;
02211         }
02212 
02213         // Free CLK and MOSI pins found. Mark them as unavailable
02214         allowed.clear(clk_index);
02215         allowed.clear(mosi_index);
02216         mbed::DigitalInOut clk(_form_factor.get(clk_index), PIN_OUTPUT, ::PullNone, 0);
02217         mbed::DigitalInOut mosi(_form_factor.get(mosi_index), PIN_OUTPUT, ::PullNone, 0);
02218 
02219         for (uint8_t miso_index = 0; miso_index < max_pins; miso_index++) {
02220             if (!allowed.get(miso_index)) {
02221                 continue;
02222             }
02223 
02224             mbed::DigitalInOut miso(_form_factor.get(miso_index));
02225             if (!mbed_tester_test(&clk, &mosi, &miso, miso_index)) {
02226                 // Pin doesn't work
02227                 continue;
02228             }
02229 
02230             // MISO found so find AUX starting from where miso left off
02231             for (uint8_t aux_index = miso_index + 1; aux_index < max_pins; aux_index++) {
02232                 if (!allowed.get(aux_index)) {
02233                     continue;
02234                 }
02235 
02236                 mbed::DigitalInOut aux(_form_factor.get(aux_index));
02237                 if (!mbed_tester_test(&clk, &mosi, &aux, aux_index)) {
02238                     // Pin doesn't work
02239                     continue;
02240                 }
02241 
02242                 // Found all 4 pins
02243                 clk_out = clk_index;
02244                 mosi_out = mosi_index;
02245                 miso_out = miso_index;
02246                 aux_out = aux_index;
02247                 clk.input();
02248                 mosi.input();
02249                 return true;
02250             }
02251 
02252             // A valid control channel was found but the system
02253             // does not have enough working pins.
02254             clk.input();
02255             mosi.input();
02256             return false;
02257         }
02258 
02259         // Set CLK and MOSI pins don't work so set them back to available
02260         clk.input();
02261         mosi.input();
02262         allowed.set(clk_index);
02263         allowed.set(mosi_index);
02264     }
02265     return false;
02266 }
02267 
02268 void MbedTester::_setup_control_pins()
02269 {
02270     _clk = new  mbed::DigitalInOut(_form_factor.get(_clk_index), PIN_OUTPUT, ::PullNone, 0);
02271     _mosi = new mbed::DigitalInOut(_form_factor.get(_mosi_index), PIN_OUTPUT, ::PullNone, 0);
02272     _miso = new  mbed::DigitalInOut(_form_factor.get(_miso_index));
02273     _aux = new  mbed::DigitalInOut(_form_factor.get(_aux_index));
02274 }
02275 
02276 void MbedTester::_free_control_pins()
02277 {
02278     if (_clk) {
02279         _clk->input();
02280         delete _clk;
02281     }
02282     _clk = NULL;
02283     _clk_index = PHYSICAL_NC;
02284     if (_mosi) {
02285         _mosi->input();
02286         delete _mosi;
02287     }
02288     _mosi = NULL;
02289     _mosi_index = PHYSICAL_NC;
02290     if (_miso) {
02291         _miso->input();
02292         delete _miso;
02293     }
02294     _miso = NULL;
02295     _miso_index = PHYSICAL_NC;
02296     if (_aux) {
02297         _aux->input();
02298         delete _aux;
02299     }
02300     _aux = NULL;
02301     _aux_index = PHYSICAL_NC;
02302     _control_valid = false;
02303 }
02304 
02305 void MbedTester::_update_control_pins()
02306 {
02307     if (_update_needed()) {
02308 
02309         if (!_control_auto) {
02310             error("Invalid control channel configuration");
02311         }
02312 
02313         _free_control_pins();
02314         if (_find_control_indexes(_clk_index, _mosi_index, _miso_index, _aux_index)) {
02315             mbed_tester_printf("Updating control pins to clk=%i, mosi=%i, miso=%i, aux=%i\r\n", _clk_index, _mosi_index, _miso_index, _aux_index);
02316             _setup_control_pins();
02317             _control_valid = true;
02318             return;
02319         } else {
02320             error("An MbedTester communication channel could not be created");
02321         }
02322     }
02323 }
02324 
02325 bool MbedTester::_update_needed()
02326 {
02327     if (!_control_valid) {
02328         return true;
02329     }
02330     // Note - mappings beyond the the first two logical banks are allowed to overlap
02331     //        with the control channels. These mappings are used for firmware updates and
02332     //        IO expander control.
02333     for (size_t i = 0; i < LogicalPinTotal; i++) {
02334         PhysicalIndex pin = _mapping[i];
02335         if ((pin == _clk_index) || (pin == _mosi_index) || (pin == _miso_index) || (pin == _aux_index)) {
02336             return true;
02337         }
02338     }
02339     return false;
02340 }
02341 
02342 void MbedTester::_reset()
02343 {
02344     for (uint32_t i = 0; i < sizeof(_mapping) / sizeof(_mapping[0]); i++) {
02345         _mapping[i] = PHYSICAL_NC;
02346     }
02347     _free_control_pins();
02348     _control_auto = true;
02349 }