माइक्रोकंट्रोलर के लिए टीडीडी। भाग 2: जासूस कैसे व्यसनों से छुटकारा पाते हैं

माइक्रोकंट्रोलर के लिए टीडीडी। भाग 1:
माइक्रोकंट्रोलर के लिए पहली TDD उड़ान भाग 2: कैसे जासूसों को माइक्रोकंट्रोलर के लिए टीडीडी निर्भरता से छुटकारा मिलता
है। भाग 3: लोहे पर चल रहा है


TDD ( – ) STM32. :


  1. .
  2. IDE .
  3. - .
  4. .

, TDD - . . - TDD . – .


-


- :


1. read , -.
2. write -.
3. erase .
4. help .
5. .


CppUTest.



– : , - UART-. UART- ASCII. - . -: .


– TDD . , ( ). .


help


– № 4 help. help UART-.


UART:


  1. .
  2. .
  3. .

P.S. .


, - : Configurator.


Serial, ( – STM32F103C8T6). , SerialSpy.


help:


TEST(Configurator, ShouldHandleHelpCommand)
{
   // Arrange –         UART
   char helpCommand[] = "help\r\n";
   LONGS_EQUAL(OK, SerialSpy_SetReceiveBuffer(serial, helpCommand, sizeof(helpCommand)));

   // Act –   
   Status status = Configurator_Handler(configurator);

   // Assert –   
   LONGS_EQUAL(OK, status);
   //  ,      UART
   char * sendBufferPtr = NULL;
   LONGS_EQUAL(OK, SerialSpy_GetSendBuffer(serial, &sendBufferPtr));
   STRCMP_EQUAL(HELP_OUTPUT, sendBufferPtr);
}

:


  • Arrange UART SerialSpy, SerialSpy_SetReceiveBuffer;
  • Act Configurator_Handler, , UART. UART;
  • Assert . SerialSpy_GetSendBuffer, STRCMP_EQUAL HELP_OUTPUT .

, : SerialSpy_SetReceiveBuffer, Configurator_Handler SerialSpy_GetSendBuffer. test fails (). Configurator_Handler Configurator .


SerialSpy_SetReceiveBuffer SerialSpy_GetSendBuffer , . , , , .


SerialSpy, Configurator Serial. SerialSpy.h , SerialSpy.c – . , , . SerialSpy :


receiveBuffer UART;
sendBuffer UART.


Configurator_Handler: , . :


SerialSpy_SetReceiveBuffer ;
SerialSpy_GetSendBuffer , .


Configurator_Handler SerialSpy
// Common.h
typedef enum
{
    OK = 0,
    FAIL = -1,
    INVALID_PARAMETERS = -4,
    OUT_OF_BOUNDS = -13,
} Status;

// Configurator.h
Status Configurator_Handler(Configurator * self);

// Configurator.c
Status Configurator_Handler(Configurator * self)
{
}

// SerialSpy.h
#include "Common.h"

Status SerialSpy_SetReceiveBuffer(Serial * self, char * data, uint32_t len);
Status SerialSpy_GetSendBuffer(Serial * self, char ** bufferPtr);

//SerialSpy.c
#include "SerialSpy.h"

typedef struct SerialStruct
{
    char receiveBuffer[SERIAL_RECEIVE_BUFFER_SIZE];
    char sendBuffer[SERIAL_SEND_BUFFER_SIZE];
} SerialStruct;

Serial * Serial_Create(void)
{
    Serial * self = (Serial*)calloc(1, sizeof(SerialStruct));
    return self;
}

void Serial_Destroy(Serial * self)
{
    if (self == NULL)
    {
        return;
    }
    free(self);
    self = NULL;
}

Status SerialSpy_SetReceiveBuffer(Serial * self, char * data, uint32_t len)
{
    if (self == NULL || data == NULL)
    {
        return INVALID_PARAMETERS;
    }
    if (len > SERIAL_RECEIVE_BUFFER_SIZE)
    {
        return OUT_OF_BOUNDS;
    }
    memcpy(self->receiveBuffer, data, len);
    return OK;
}

Status SerialSpy_GetSendBuffer(Serial * self, char ** bufferPtr)
{
    if (self == NULL || bufferPtr == NULL)
    {
        return INVALID_PARAMETERS;
    }
    *bufferPtr = self->sendBuffer;
    return OK;
}

, SerialSpy UART. TDD unit- . . Configurator STM32. , -, «» Visual Studio .


test-fails test-passes


test-passes Configurator_Handler. UART Serial_ReceiveCommand . help , help, Serial_SendResponse.


Configurator UART Serial, Serial, Configurator_CreateSerial*. setup() teardown() .


help
// Configurator.h
//    `help`     `Serial`
#include "Serial.h"

#define HELP_OUTPUT \
"Command list:\r\n \
    - help\r\n \
    - read:  <flash_address_in_hex>\r\n \
    - write: <flash_address_in_hex> <data_to_write>\r\n \
    - erase: <flash_page_number_to_erase>\r\n>"

Configurator * Configurator_Create(Serial * serial);

// Configurator.c
//       UART  Serial  Configurator
typedef struct ConfiguratorStruct
{
    char command[SERIAL_RECEIVE_BUFFER_SIZE];
    Serial * serial;
} ConfiguratorStruct;

static const char helpCommand[] = "help";

//   Serial   (    )
Configurator * Configurator_Create(Serial * serial)
{
    if (serial == NULL)
    {
        return NULL;
    }
    Configurator * self = (Configurator*)calloc(1, sizeof(ConfiguratorStruct));
    if (self == NULL)
    {
        return NULL;
    }
    self->serial = serial;
    return self;
}

//    Configurator_Handler
Status Configurator_Handler(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //      UART
    Status status = Serial_ReceiveCommand(self->serial, self->command);
    if (status != OK)
    {
        //    UART   NO_DATA
        return status;
    }
    //   
    if (strstr(self->command, helpCommand) == NULL)
    {
        return UNSUPPORTED;
    }
    Status status = Serial_SendResponse(self->serial, HELP_OUTPUT);
    return status;
}

// ConfiguratorTests.cpp
TEST_GROUP(Configurator)
{
    Configurator * configurator = NULL;
    Serial * serial = NULL;
    void setup()
    {
        serial = Serial_Create();
        configurator = Configurator_Create(serial);
    }
    void teardown()
    {
        Configurator_Destroy(configurator);
    }
};  

Serial, . . Configurator_Handler. SerialSpy, . SerialSpy.c Serial.cSerial.h:


#pragma once

#include "Common.h"

#define SERIAL_RECEIVE_BUFFER_SIZE   32   //    
#define SERIAL_SEND_BUFFER_SIZE     256   //     

typedef struct SerialStruct Serial;

Serial * Serial_Create(void);
void Serial_Destroy(Serial * self);

//       UART
//  self –     Serial
//  commandPtr –   ,       
//  :
//  OK –       
//  NO_DATA –      
 Status Serial_ReceiveCommand(Serial * self, char * commandPtr);

//    UART
//  self –     Serial
//  responsePtr –     
//  :
//  OK –    ,  – FAIL
Status Serial_SendResponse(Serial * self, char * responsePtr);

//    UART
//  self –     Serial
//  :
//  OK –    ,  – FAIL
Status Serial_Clear(Serial * self);

Serial.h ProductionCodeLib. Tests SerialSpy.c Serial_ReceiveCommand Serial_SendResponse, UART .


/ SerialSpy.c
// ... some code
static bool IsEndOfString(char * buffer)
{
    for (int i = 0; i < SERIAL_RECEIVE_BUFFER_SIZE; i++)
    {
        if (buffer[i] == '\n')
        {
            return true;
        }
    }
    return false;
}

Status Serial_ReceiveCommand(Serial * self, char * commandPtr)
{
    if (self == NULL || commandPtr == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //       UART
    uint32_t commandLen = strlen(self->receiveBuffer);
    if (commandLen == 0)
    {
        return NO_DATA;
    }
    //      `\n`
    bool isEndOfString = IsEndOfString(self->receiveBuffer);
    if (isEndOfString == false)
    {
        return NO_DATA;
    }
    //        `\n`       UART
    strncpy(commandPtr, self->receiveBuffer, commandLen);
    self->receiveBuffer[SERIAL_RECEIVE_BUFFER_SIZE – 1] = 0;
    return OK;
}

Status Serial_SendResponse(Serial * self, char * responsePtr)
{
    if (self == NULL || responsePtr == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //     
    uint32_t responseLen = strlen(responsePtr);
    if (responseLen > SERIAL_SEND_BUFFER_SIZE)
    {
        return OUT_OF_BOUNDS;
    }
    //      
    strncpy(self->sendBuffer, responsePtr, responseLen);
    self->sendBuffer[SERIAL_SEND_BUFFER_SIZE – 1] = 0;
    return OK;
}
// ... some code

/ SerialSpy.c . UART :


  • strncpy;
  • strlen ( \n). strncpy , .

:


..
OK (2 tests, 2 ran, 5 checks, 0 ignored, 0 filtered out, 0 ms)

help , . test-passes. refactor.


refactor


, . , : , . : .


, , . - «», . , .


Configurator_Handler static HandleCommand. : ( help).


// Configurator.c
static Status HandleHelpCommand(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    Status status = Serial_SendResponse(self->serial, HELP_OUTPUT);
    return status;
}

static Status HandleCommand(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //   help
    if (strstr(self->command, helpCommand) != NULL)
    {
        return HandleHelpCommand(self);
    }
    //   
    return UNSUPPORTED;
}

Status Configurator_Handler(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //      UART
    Status status = Serial_ReceiveCommand(self->serial, self->command);
    if (status != OK)
    {
        //    UART   NO_DATA
        return status;
    }
    //   
    status = HandleCommand(self);
    if(status != OK)
    {
        return status;
    }
    return status;
}  

refactor, fails-passes-refactor.


Configurator_Handler :


read – -;
write – -;
erase – -.


, , gitlab.


-.


-


FlashSpy Configurator . write :


write: <flash_address_in_hex> <data_to_write>\r\n


write:


TEST(Configurator, ShouldHandleWriteFlashCommand)
{
    // Arrange
    //      write
    uint32_t expectedFlashData = 0x11223344;
    //         UART
    char writeFlashCommand[] = "write: 0x10000 0x11223344\r\n";
    LONGS_EQUAL(OK, SerialSpy_SetReceiveBuffer(serial, writeFlashCommand, sizeof(writeFlashCommand)));

    // Act
    Status status = Configurator_Handler(configurator);

    // Assert
    //  
    LONGS_EQUAL(OK, status);
    //  ,   -
    uint32_t * flashPtr = NULL;
    LONGS_EQUAL(OK, FlashSpy_GetFlashPtr(&flashPtr, 0x10000));
    LONGS_EQUAL(expectedFlashData, *flashPtr);
}

4 . , - . Flash.h:


// Flash.h
#pragma once

#include "Common.h"

#define FLASH_PAGE_COUNT    0x80
#define FLASH_PAGE_SIZE     0x400
#define FLASH_SIZE          FLASH_PAGE_COUNT * FLASH_PAGE_SIZE   // 128 Kb

Status Flash_Init(void);
Status Flash_DeInit(void);

Status Flash_Write(uint32_t address, uint32_t data);
Status Flash_Read(uint32_t address, uint32_t * dataPtr);
Status Flash_Erase(uint8_t pageNumber);

Flash.h FlashSpy.c : - uint8_t flash[FLASH_SIZE], FLASH_SIZE . - FLASH_SIZE, Flash_Read, Flash_Write Flash_Erase.


FlashSpy.c Tests FlashSpy_GetFlashPtr address . .


, , , - FlashSpy.c. flashMemory ( - STM32F103C8):


  • Flash_Read 32 , flashMemory.
  • Flash_Write 32 flashMemory.
  • Flash_Erase flashMemory STM32F103C8 0xFF memset.

- Configurator.


, , `FlashSpy`
// FlashSpy.h
#pragma once
#include "Flash.h"
Status FlashSpy_GetFlashPtr(uint32_t ** flashMemoryPtr, uint32_t address);

// FlashSpy.c
static uint8_t * flashMemory = NULL;

// -
Status FlashSpy_GetFlashPtr(uint32_t ** flashMemoryPtr, uint32_t address)
{
    if (flashMemory == NULL)
    {
        return WRONG_CONDITION;
    }
    if (flashMemoryPtr == NULL || address >= FLASH_SIZE)
    {
        return INVALID_PARAMETERS;
    }
    *flashMemoryPtr = (uint32_t*)&flashMemory[address];
    return OK;
}

//     
Status Flash_Init(void)
{
    flashMemory = (uint8_t*)malloc(FLASH_SIZE);
    if (flashMemory == NULL)
    {
        return FAIL;
    }
    // ,  -   (   0b1)
    memset(flashMemory, 0xFF, FLASH_SIZE);
    return OK;
}

Status Flash_DeInit(void)
{
    if (flashMemory == NULL)
    {
        return OK;
    }
    free(flashMemory);
    flashMemory = NULL;
    return OK;
}

Status Flash_Write(uint32_t address, uint32_t data)
{
    if (flashMemory == NULL)
    {
        return WRONG_CONDITION;
    }
    if (address >= FLASH_SIZE)
    {
        return INVALID_PARAMETERS;
    }
    //   :  0b1  0b0,      Flash_Erase
    *(uint32_t*)(flashMemory + address) &= data;
    return OK;
}

Status Flash_Read(uint32_t address, uint32_t * dataPtr)
{
    if (flashMemory == NULL || dataPtr == NULL)
    {
        return WRONG_CONDITION;
    }
    if (address >= FLASH_SIZE)
    {
        return INVALID_PARAMETERS;
    }
    *dataPtr = *(uint32_t*)(flashMemory + address);
    return OK;
}

Status Flash_Erase(uint8_t pageNumber)
{
    if (flashMemory == NULL)
    {
        return WRONG_CONDITION;
    }
    if (pageNumber >= FLASH_PAGE_COUNT)
    {
        return INVALID_PARAMETERS;
    }
    uint32_t offset = pageNumber * FLASH_PAGE_SIZE;
    memset(flashMemory + offset, 0xFF, FLASH_PAGE_SIZE);
    return OK;
}

Flash_Write «», - ( 0b1).


- setup() teardown() ConfiguratorTests.cpp.


Flash
TEST_GROUP(Configurator)
{
    Configurator * configurator = NULL;
    Serial * serial = NULL;

    void setup()
    {
        serial = Serial_Create();
        configurator = Configurator_Create(serial);
        Flash_Init();
    }
    void teardown()
    {
        Configurator_Destroy(configurator);
        Flash_DeInit();
    }
};

UNSUPPORTED, . . Configurator_Handler write. test fails.


d:\exampletdd\tests\tests\configuratortests.cpp(66): error: Failure in TEST(Configurator, ShouldHandleWriteFlashCommand)
          expected < 0 0x00000000>
          but was  <-9 0xfffffff7>
...
Errors (1 failures, 3 tests, 3 ran, 8 checks, 0 ignored, 0 filtered out, 5 ms)

test-passes write Configurator.c. HandleWriteCommand:


  • , 32 ;
  • ( -);
  • - Flash_Write;
  • Serial_SendResponse.

// Configurator.c
#include "Flash.h"
// ... some code
#define LEN_MIN_ARG         sizeof("0x0")
#define LEN_WRITE_COMMAND   sizeof(writeCommand) + LEN_MIN_ARG + LEN_MIN_ARG
// ... some code
static const char writeCommand[] = "write:";
static const char writeResponse[] = "Written successfully\r\n>";
// ... some code
static Status HandleWriteCommand(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //    
    uint32_t commandLen = strlen(self->command);
    if (commandLen < LEN_WRITE_COMMAND)
    {
        return INVALID_PARAMETERS;
    }
    //   -
    char * flashAddressPtr = self->command + sizeof(writeCommand);
    uint32_t flashAddress = strtol(flashAddressPtr, (char**)NULL, 16);
    if (flashAddress > FLASH_SIZE)
    {
        return INVALID_PARAMETERS;
    }
    //      -
    char * dataAddressPtr = strchr(self->command + sizeof(writeCommand), ' ');
    uint32_t data = strtol(dataAddressPtr, (char**)NULL, 16);
    //   -
    Status status = Flash_Write(flashAddress, data);
    if (status != OK)
    {
        return status;
    }
    //      UART
    status = Serial_SendResponse(self->serial, (char*)writeResponse);
    return status;
}

static Status HandleCommand(Configurator * self)
{
    if (self == NULL)
    {
        return INVALID_PARAMETERS;
    }
    //  help
    if (strstr(self->command, helpCommand) != NULL)
    {
        return HandleHelpCommand(self);
    }
    //  write
    else if (strstr(self->command, writeCommand) != NULL)
    {
        return HandleWriteCommand(self);
    }
    //  
    return UNSUPPORTED;
}

test-passes.


...
OK (3 tests, 3 ran, 9 checks, 0 ignored, 0 filtered out, 0 ms)

refactoring, . - .



, - . 5 - ( ). .



TDD - . . , , .


Configurator SerialSpy FlashSpy UART -.
- , . .


, . . , Serial.h Flash.h.


, , . , unit- ShouldHandleWriteFlashCommand . , - . .


Serial.c Flash.c STM32F103C8, , , . «» , .




Raccoon Security – «» , , , .


All Articles