posilani dat

Dependencies:   FatFileSystemCpp mbed PowerControl USBHostLite

main.cpp

Committer:
legwinskij
Date:
2015-11-10
Revision:
17:ca53e6d36163
Parent:
15:baa2672a9b38
Child:
18:7acae34b518d

File content as of revision 17:ca53e6d36163:

/* BRIEF:
 * Connects to wifi and listen on ip given by dhcp on port 2000
 *
 * Commands are send in for #X where X is from {S,E,T,R}, all commands are
 * confirmed by mbed by sending #A
 *
 * Use #S to start saving data, #E to stop saving. This can be done repeatedly,
 * mbed saves the data into separated files and generates new swimmer id
 * At the end, use #T to start data transfer, the format of transmitted data is:
 *
 * Header for each swimmer:
 * (int) -1 (int) -1 (int) swimmer_id
 * Data itself
 * (char) 0xAA (int) count 3*(short) acc 3*(float) gyro
 * End of swimmer block
 * (int) -1 (int) -1  
 *
 * where count is number starting on 0, incremented on every packet
 * 0xAA is a sync byte used to avoid confusion when some bytes are lost during
 * transmission (UART on faster reates seems to be unstable)
 * 
 * CHANGELOG 22/10/2015
 * - Refactored code
 * - Now using USB flash instead of SD card 
 * - SIZE of packets to be saved at once changed to 32 (from 1000, saving took too much time, effectively loosing measurements)
 * - Using fwrite to write 32 packets at once (packet size = 16 bytes -> 32*16 = 512 bytes -> USB flash sector size is 512 bytes, thus maximizing fwrite effectivity
 * - Saving of 32 packets takes about 3,5 ms
 * KNOWN ISSUES:
 * - Opening USB disk takes some time, couple first measurements not valid (perhaps open next file right when saving stops ?)
 */

// Includes ====================================================================

#include "mbed.h"
#include "PowerControl.h"
#include "EthernetPowerControl.h"
#include "L3GD20_init.h"
#include "math.h"
#include "stdint.h"
#include "DirHandle.h"
#include "MSCFileSystem.h"
#include "L3GD20.h"
#include "adc.h"
#include "utils.h"
#include "wifi.h"
#include <stdio.h>

// Defines =====================================================================

/* credentials for wifi */
#define SSID                "BRNET"
#define PASS                "Fuhu27che9"
#define SECURITY            WPA

/* ADC & data acquisition related stuff */
#define SAMPLE_RATE         700000                                              // Sample rate for ADC conversion
#define PERIOD              0.01                                                // Setting the period of measuring, 0.01 menas 100 times per second
#define SIZE                32                                                  // Setting number of instance in array - for saving to SD card
#define BUFFER_SIZE        (sizeof(int) + sizeof(short)*6)                      //size of one data block

/* mass storage disk name */
#define FSNAME "usb"

/* Commands mbed understands */
#define SAVING_START        'S'
#define SAVING_STOP         'E'
#define TRANSFER_START      'T'
#define CHECK_READY         'R'

/* Function like macros for leds (bleh) */
#define leds_off() { led_measuring = led_sending = led_working = led_saving = 0; }
#define leds_error() { led_measuring = led_sending = led_working = led_saving = 1; }

// Watchdog class ==============================================================

class Watchdog {
public:
    /* Kick the watchdog with time period setting */
    void kick(float s) {
        LPC_WDT->WDCLKSEL = 0x1;                                                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;                                    // WD has a fixed /4 prescaler, PCLK default is /4
        LPC_WDT->WDTC = s * (float)clk;
        LPC_WDT->WDMOD = 0x3;                                                   // Enabled and Reset
        kick();
    }

    /* Kick the watchdog */
    void kick() {
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
};

// Objects & vars ==============================================================

Watchdog w;                                                                     // Initialize watchdogs
Ticker Saving_Ticker;                                                           // Tickers for interrupts on measuring
ADC adc(SAMPLE_RATE, 1);                                                        // Initialize ADC to maximum SAMPLE_RATE and cclk divide set to 1   originally MMA7361L
Wifi wifi(p13, p14, p11, p12, p23);                                             // Wifly module
I2C i2c(p28, p27);                                                              // NEW function GYRO connection originally L3G4200D

/* LED indicators */
DigitalOut led_measuring(LED1);
DigitalOut led_sending(LED2);
DigitalOut led_working(LED3);
DigitalOut led_saving(LED4);

// Added for test purposes
DigitalOut flagSetNotify(p9);
DigitalOut measureNotify(p10);

/* USB & saving related stuffs */
FILE *gfp;                                                                      // Global file pointer
MSCFileSystem logger(FSNAME);                                                   // Initialize USB flash disk
char fname[40];                                                                 // Variable for name of Text file saved on USB flash disk
static volatile uint64_t absolute = 0;                                          // Variable for numbering saved data
volatile int relative = 0;
volatile short swimmer_id = 0;
volatile short last_send = 0;
volatile bool measuringFlag = 0;                                                // Flag that is set with interrupt

/* Accelerometer buffers */
short int acc_x[SIZE];
short int acc_y[SIZE];
short int acc_z[SIZE];

/* Gyroscope buffers */
short int gyro_x[SIZE];
short int gyro_y[SIZE];
short int gyro_z[SIZE];

// Functions -> I2C ============================================================

/* Reads byte from given address */
char readByte(char address, char reg)
{
    char result;                                                                // Buffer for returning byte
    i2c.start();                                                                // Start i2c transfer
    i2c.write(address);                                                         // Slave address with direction=write
    i2c.write(reg);                                                             // Register address
    i2c.start();                                                                // Break transmission to change bus direction
    i2c.write(address + 1);                                                     // Slave address with direction=read [bit0=1]
    result = i2c.read(0);                                                       // Byte we want to read
    i2c.stop();                                                                 // Stop i2c operation
    return (result);                                                            // Return byte
}

/* Sends 1 byte to an I2C address */
void writeByte(char address, char reg,char value)
{
    i2c.start();                                                                // Start i2c transfer
    i2c.write(address);                                                         // Slave address
    i2c.write(reg);                                                             // Register address
    i2c.write(value);                                                           // Value to be written
    i2c.stop();                                                                 // Stop i2c operation
}

// Functions -> Init ===========================================================

/* Prepares board for operation (adc's, gyroscope etc.) */
void boardInit (void)
{
    /* L3GD20 Gyroscope init */
    writeByte(L3GD20_ADDR,gCTRL_REG1,0x0F);                                     // Set ODR to 95Hz, BW to 12.5Hz, enable axes and turn on device
    writeByte(L3GD20_ADDR,gCTRL_REG4,0x10);                                     // Full scale selected at 500dps (degrees per second)
    wait(1);                                                                    // Wait for settings to stabilize

    /* Accelerometer init */
    adc.setup(p18,1);                                                           // Set up ADC on pin 18
    adc.setup(p19,1);                                                           // Set up ADC on pin 19
    adc.setup(p20,1);                                                           // Set up ADC on pin 20

    /* Rest of the init */
    PHY_PowerDown();                                                            // Disable ETH PHY to conserve power (about 40mA)
    leds_off();                                                                 // Turn off all leds
}

// Functions -> Measuring ======================================================

/* Main measuring function */
void measuring(void)
{
    /* Vars */
    char xL, xH, yL, yH, zL, zH;                                                // Gyro high/low bytes
    char buffer[SIZE][BUFFER_SIZE];                                             // Buffer
    int pos = 0;                                                                // Position

    /* Read ACC_X */
    adc.start();                                                                // Starting ADC conversion
    adc.select(p18);                                                            // Measure pin 18
    while(!adc.done(p18));                                                      // Wait for it to complete
    acc_x[relative] = (short) adc.read(p18);                                    // Read ACC_X value
    /* Read ACC_Y */
    adc.start();                                                                // Again
    adc.select(p19);                                                            // Measure pin 19
    while(!adc.done(p19));                                                      // Wait for it to complete
    acc_y[relative] = (short) adc.read(p19);                                    // Read ACC_Y value
    /* Read ACC_Z */
    adc.start();                                                                // Again
    adc.select(p20);                                                            // Measure pin 20
    while(!adc.done(p20));                                                      // Wait for it to complete
    acc_z[relative] = (short) adc.read(p20);                                    // Read ACC_Z value

    /* Read Gyro_X */
    xL=readByte(L3GD20_ADDR,gOUT_X_L);                                          // Read GYRO_X Low byte
    xH=readByte(L3GD20_ADDR,gOUT_X_H);                                          // Read GYRO_X High byte
    /* Read Gyro_X */
    yL=readByte(L3GD20_ADDR,gOUT_Y_L);                                          // Read GYRO_Y Low byte
    yH=readByte(L3GD20_ADDR,gOUT_Y_H);                                          // Read GYRO_Y High byte
    /* Read Gyro_X */
    zL=readByte(L3GD20_ADDR,gOUT_Z_L);                                          // Read GYRO_Z Low byte
    zH=readByte(L3GD20_ADDR,gOUT_Z_H);                                          // Read GYRO_Z High byte
    /* Add Gyroscope values to global buffer */
    gyro_x[relative] = (xH<<8) | (xL);                                          // 16-bit 2's complement GYRO_X
    gyro_y[relative] = (yH<<8) | (yL);                                          // 16-bit 2's complement GYRO_Y
    gyro_z[relative] = (zH<<8) | (zL);                                          // 16-bit 2's complement GYRO_Z

    /* Increment counters */
    absolute++;                                                                 // Increment absolute counter
    relative++;                                                                 // Increment relative counter

    /* After our buffers are full save the data */
    if ( absolute % SIZE == 0 )
    {
        /* Flip led_saving state */
        led_saving = !led_saving;

        /* Handle file error */
        if (gfp == NULL) {
            printf("\r\nUnable to append data to file %s", fname);              // Notify user
            return;                                                             // Return
        }

        /* Iterate all buffer elements */
        for (int k = 0; k < SIZE; k++)
        {
            pos = absolute-SIZE+k;                                              // Increment position
            toBytes(buffer[k], &pos, sizeof(int));                              // Append data to buffer in byte form
            toBytes(buffer[k]+sizeof(int), &acc_x[k], sizeof(short));
            toBytes(buffer[k]+sizeof(int) + sizeof(short), &acc_y[k], sizeof(short));
            toBytes(buffer[k]+sizeof(int) + sizeof(short)*2, &acc_z[k], sizeof(short));
            toBytes(buffer[k]+sizeof(int) + sizeof(short)*3, &gyro_x[k], sizeof(short));
            toBytes(buffer[k]+sizeof(int) + sizeof(short)*4, &gyro_y[k], sizeof(short));
            toBytes(buffer[k]+sizeof(int) + sizeof(short)*5, &gyro_z[k], sizeof(short));                              
        }
        
        //measureNotify = 1;                                                    // Used for saving debug
        /* Write 32 buffer lines (16 bytes) to file (512 bytes total -> one block) */
        fwrite(buffer, SIZE, BUFFER_SIZE, gfp);                                 
        //measureNotify = 0;                                                    // Used for saving debug
    
        /* Reset relative counter */
        relative = 0;
    }
}

/* Sets the measuring flag */
void setMeasuringFlag(void)
{
    //flagSetNotify = 1;                                                        // Used for saving debug
    measuringFlag = 1;                                                          // Set measuring flag
    //flagSetNotify = 0;                                                        // Used for saving debug
}

/* Sees whether giver file exists on flash disk */
bool doesFileExist(const char *filename)
{
    /* Dir related structs & vars */
    DIR *dir;                                                                   // Prepare directory handle
    struct dirent *file;                                                        // Directory entry structure
    dir = opendir("/usb");                                                      // Open root of usb flash disk                                                      
    
    /* Iterate all available files in root directory */
    while((file = readdir(dir)) != NULL)                                        // Incrementally points to next files, until NULL is reached
    {
        /* Check if it's file we are looking for */
        if(strcmp(filename+5, file->d_name) == 0)                               // +5 moves us beyond /usb/, not cool I know...
        {
            closedir(dir);                                                      // Close dir & return true
            return true;   
        }
    }
    
    /* If file is not present */
    closedir(dir);                                                              // Close dir & return false
    return false;                                                               // If not, return false
} 

// Functions -> Commands =======================================================

/* Starts to acquire data from sensors */
void startSaving(void)
{
    /* Open global file with current swimmer ID */
    gfp = fopen(fname, "wb");                                                   // Try to open that file
    if(gfp == NULL) {
        leds_error();                                                           // Turn on all leds
        printf("\r\nUnable to open file %s for writing", fname);                // Notify user
        return;                                                                 // Exit function
    }

    /* Prepare file & vars for data acquisition */
    fprintf(gfp, "%c%c%c", -1, -1, swimmer_id);                                 // Append header to current swimmer output file

    /* Reset counters */
    absolute = 0;                                                               // Reset absolute counter
    relative = 0;                                                               // Reset relative counter

    /* Set timer */
    Saving_Ticker.attach(&setMeasuringFlag, PERIOD);                            // Attach function that periodically sets the flag
}

/* Sends acquired data to USB flash */
void stopSaving(void)
{
    /* Stop saving */
    Saving_Ticker.detach();                                                     // Stop setting measuring flag

    /* Try to append data left in buffers */
    if(gfp == NULL) {
        leds_error();                                                           // Turn on all leds
        printf("\r\nUnable to open file %s before sending data", fname);        // Notify user
        return;                                                                 // Exit function
    }

    /* Append data left to buffer */
    int base = ((absolute - (absolute%SIZE)) < 0) ? 0 : absolute - (absolute%SIZE);
    char buffer[relative][BUFFER_SIZE];                                         // packet array
    
    /* Iterate all array elements */
    for (int k = 0; k < relative; k++) {
        int pos = base+k;
        toBytes(buffer[k], &pos, sizeof(int));
        toBytes(buffer[k]+sizeof(int), &acc_x[k], sizeof(short));
        toBytes(buffer[k]+sizeof(int) + sizeof(short), &acc_y[k], sizeof(short));
        toBytes(buffer[k]+sizeof(int) + sizeof(short)*2, &acc_z[k], sizeof(short));
        toBytes(buffer[k]+sizeof(int) + sizeof(short)*3, &gyro_x[k], sizeof(short));
        toBytes(buffer[k]+sizeof(int) + sizeof(short)*4, &gyro_y[k], sizeof(short));
        toBytes(buffer[k]+sizeof(int) + sizeof(short)*5, &gyro_z[k], sizeof(short));
    }
    
    /* Write what's left */
    fwrite(buffer, relative, BUFFER_SIZE, gfp);                                 // Write all data at once

    /* Append EOF and close file */
    fprintf(gfp, "%c%c", -1,-1);                                                // Write EOF characters
    fclose(gfp);                                                                // Close file

    /* Prepare for next swimmer */
    swimmer_id++;                                                               // Increment swimmer ID
    sprintf(fname, "/usb/swimmer%d.txt", swimmer_id);                           // Update current file name
    remove(fname);                                                              // If file with such ID exists remove it to avoid reading old data
}

/* Sends acquired data via Wi-Fi */
void transfer(void)
{
     /* Vars */
    char name[30];                                                              // File name buffer  
    
    /* File transfer prerequisites */
    fclose(gfp);                                                                // Close curretly opened file
    int requested_id = wifi.readByte();                                         // Get byte containing requested file ID
    sprintf(name, "/usb/swimmer%d.txt", requested_id);                          // Create file name based on current swimmer ID
    
    /* Handle transfer */
    if(doesFileExist(name))                                                     // At first check whether file exists (fopen used to freeze mbed)
    {
        /* Send ACK (should make this more abstract) */
        wifi.sendByte('#');
        wifi.sendByte('A');
        wait_ms(50);                                                            // Timeout is used to make sure C# gets ready (sockets are messy, flushing is pain)
        /* Actually try to send file */                                         
        printf("\r\nSending %s", name);                                         // Notify user which user is being sent
        if (wifi.sendFile(name, requested_id))                                  // Send !
        {
            leds_error();                                                       // Handle error
            printf("\r\nUnable to send data");                                  // Notify user via text also
        }
        else
        {
            printf("\r\nSwimmer %d finished", requested_id);                    // Otherwise all is AOK
        }  
    }
    else
    {
        /* In case file doest not exist send NACK */
        wifi.sendByte('#');                                                     
        wifi.sendByte('F');
        printf("\r\nRequest non-existing file...");
    }
}

// Main ========================================================================

int main()
{
    /* Begin by initialization */
    printf("\r\nBoot...");                                                      // Notify user that board is booting
    boardInit();                                                                     // Initialize board
    printf("\r\nReady...");                                                     // Notify user that board is ready

    /* Set zeroth swimmer name */
    sprintf(fname, "/usb/swimmer%d.txt", swimmer_id);                           // Prepare zeroth swimmer filename

    /* Main while */
    while (1)
    {
        /* Read command from wifly */
        char cmd = wifi.getCmd();
        
        /* Master switch */
        switch (cmd) {
            /* start measuring data periodically and save them info file */
            case SAVING_START:
            {
                leds_off();                                                     // Turn off all leds
                startSaving();                                                  // Actually start saving
                printf("\r\nSaving swimmer %d...", swimmer_id);                 // Notify user
                led_measuring = 1;                                              // Turn on led_measuring
                break;                                                          // Break from switch
            }

            /* stop saving data */
            case SAVING_STOP:
            {
                leds_off();                                                     // Turn off all leds
                stopSaving();                                                   // Actually stop saving
                printf("\r\nStopped...");                                       // Notify user
                break;                                                          // Break from switch
            }

            /* Send all data */
            case TRANSFER_START:
            {
                leds_off();                                                     // Turn off all leds
                led_sending = 1;                                                // Turn on led_sending
                printf("\r\nSending data...");                                  // Notify user that data is being sent
                transfer();                                                     // Actually transfer data
                printf("\r\nSending finished...");                              // Notify user that data was sent successfully
                leds_off();                                                     // Turn off all leds again
                break;                                                          // Break from switch
            }

            /* Ready || Nothing on serial */
            case 'R':
            case 'N':
            {
                /* Handle data measuring */
                if(measuringFlag)                                               // Wait for timer to set the flag again and again
                {
                    measuring();                                                // Measure !
                    measuringFlag = 0;                                          // Reset flag
                }
                break;                                                          // Break from switch
            }

            /* Everything else is ballast */
            default :
            {
                leds_error();                                                   // Turn on all leds
                printf("\r\nCommand %c is unknown!", cmd);                      // Notify user
                break;                                                          // Break from switch
            }
        }
    }
}