Sony's LANC camera control protocol project.

Dependencies:   aconno_LANC aconno_bsp aconno_SEGGER_RTT

main.cpp

Committer:
jurica238814
Date:
2018-08-28
Revision:
12:69dbd9ef58e8
Parent:
11:e5f11b96088e

File content as of revision 12:69dbd9ef58e8:

/*
 * Example to demonstrate usage of the nrf52's I2S interface
 *
 * Made by Jurica Resetar @ aconno
 * jurica_resetar@yahoo.com
 * More info @ aconno.de
 *
 * All rights reserved
 *
 */
 
#include "mbed.h"
#include "acd52832_bsp.h"
#include "ble/BLE.h"
#include "GapAdvertisingData.h"
#include "AckService.h"

#define PRINT_ON_RTT    (1)

#ifdef PRINT_ON_RTT
    #include "SEGGER_RTT.h"
    #define printf(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
    #define printf(...)
#endif

#define MY_BUF_SIZE     (13*8)
#define LANC_H          0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF    /* 13 B */
#define LANC_H_L        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,\
                        0x00, 0x00, 0x00, 0x00, 0x00, 0xFF    /* 13 B */
#define LANC_L          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00    /* 13 B */

/*
 *  Bitovi na I2S bus idu od MSBa do LSBa
 */

#define LANC_COMMAND_PIN    (p2)   // Pin connected to Tr to pull lanc bus down/up     2/26
#define LANC_PIN            (p3)   // Lanc bus pin (to scan for START/STOP bits)        3/25
#define LED_ON              (0)
#define LED_OFF             (1)
#define MSD_SIZE            (29)             /* Manufacturer Specific Data lenght (in B) */

uint8_t MSD[MSD_SIZE] = {0x59, 0x00, 0xDD, 0x4E, 0xCD, 0xC5, 0x5E, 0xA3, 0x43, 0x67, 0x8B, 0x84, 0x94, 0xFF, 0xBA, 0xD9, 0x29, 0xC6};
uint8_t myMacAddress[6] = {};
ACKService<2> *ackServicePtr;
BLE &ble = BLE::Instance();

void sendCommand(uint32_t *commandType, uint32_t *command);
GapAdvertisingData advData = GapAdvertisingData();

DigitalOut alive(p23);
DigitalOut connectedLED(p24);
DigitalOut testLED(p22);

uint8_t normalCommand[MY_BUF_SIZE] __attribute__ ((aligned (32))) = {LANC_L,LANC_L,LANC_L,LANC_H, LANC_H,LANC_L,LANC_L,LANC_L};
uint8_t zoomCommand[MY_BUF_SIZE] __attribute__ ((aligned (32))) = {LANC_L,LANC_L,LANC_L,LANC_H, LANC_L,LANC_H,LANC_L,LANC_L};
uint8_t startStop[MY_BUF_SIZE] __attribute__ ((aligned (32))) = {LANC_H,LANC_H,LANC_L,LANC_L,LANC_H,LANC_H,LANC_L,LANC_L};
uint8_t zoomIn[MY_BUF_SIZE] __attribute__ ((aligned (32))) = {LANC_H,LANC_L,LANC_L,LANC_H,LANC_H,LANC_H,LANC_L,LANC_L};     // Tele
uint8_t zoomOut[MY_BUF_SIZE] __attribute__ ((aligned (32))) = {LANC_H,LANC_H,LANC_L,LANC_H,LANC_H,LANC_H,LANC_L,LANC_L};    // Wide

uint32_t *normalCmdAddr = (uint32_t*)normalCommand;
uint32_t *zoomCmdAddr = (uint32_t*)zoomCommand;
uint32_t *startStopAddr = (uint32_t*)startStop;
uint32_t *zoomInAddr = (uint32_t*)zoomIn;
uint32_t *zoomOutAddr = (uint32_t*)zoomOut;

uint8_t volatile i2sFlag = 0;   
uint8_t state = 0;  /* 1 -> Send command type, 0 -> send command */

InterruptIn button(LANC_PIN);
Timer frameTimer;

void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params){
    //connectedLED = LED_ON;
    ble.gap().stopAdvertising();
}

void onDataWrittenCallback(const GattWriteCallbackParams *params) {
    /*
    switch(params->data[0]){
        case 0x00:{
            sendCommand(normalCmdAddr, startStopAddr);        
            alive = !alive;
    
            break;
        }
        case 0x01:{
            sendCommand(zoomCmdAddr, zoomOutAddr);        
            connectedLED = !connectedLED;
    
            break;
        }
        case 0x02:{
            sendCommand(zoomCmdAddr, zoomInAddr);        
            testLED = !testLED;
            break;
        }
        default: break;
    }
    */
    uint32_t commandType[MY_BUF_SIZE];
    uint32_t command[MY_BUF_SIZE];
    uint8_t counter;
    
    printf("Data[0]: %d\n", params->data[0]);
    printf("Data[1]: %d\n", params->data[1]);
    
    for(counter = 0; counter < 8; counter++)
    {
        (params->data[0] & (1 << 7 - counter)) ? commandType[counter] = LANC_H : 
                                             commandType[counter] = LANC_L;
    }
    
    for(counter = 0; counter < 8; counter++)
    {
        (params->data[0] & (1 << 7 - counter)) ? command[counter] = LANC_H : 
                                             command[counter] = LANC_L;
    }
    
    sendCommand(commandType, command);
    
    return;
}

/**
 * Restart Advertising on disconnection
 */
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
    connectedLED = LED_OFF;
    BLE::Instance().gap().startAdvertising();
}


/**
 * This function is called when the ble initialization process has failed
 */
void onBleInitError(BLE &ble, ble_error_t error){
    /* Avoid compiler warnings */
    (void) ble;
    (void) error;
    /* Initialization error handling should go here */
}

/**
 * Callback triggered when the ble initialization process has finished
 */
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params){
    BLE&        ble   = params->ble;  
    uint8_t init_values[2];
    
   
    /* Get my MAC address */
    BLEProtocol::AddressType_t temp_address_type;
    ble.gap().getAddress(&temp_address_type, myMacAddress);
    ackServicePtr = new ACKService<2>(ble, init_values);
    
    ble.gap().onDisconnection(disconnectionCallback);
    ble.gap().onConnection(onConnectionCallback);         
    ble.gattServer().onDataWritten(onDataWrittenCallback);
    
    /* setup advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)MSD, MSD_SIZE);
    ble.gap().setAdvertisingInterval(500);  // --> Has to be at least 100ms!
    ble.gap().startAdvertising();
}

void i2sReady(){
    /* Interrupt handler */
    i2sFlag = 1;
}

uint8_t waitForStartBit(){
    static uint8_t firstInt = 1;
    static int lastIntTime_us = 0;
    
    while(!i2sFlag);       // Wait for the interrupt to change the flag
    if(firstInt){
        firstInt = 0;
        frameTimer.start();
    }
    lastIntTime_us = frameTimer.read_us();
    frameTimer.reset();
    i2sFlag = 0;
    
    if(lastIntTime_us > 10000){
       return 1; 
    }
    else{
        return 0;
    }
}

void sendi2sData(){
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    NRF_I2S->ENABLE = 1;
    NRF_I2S->TASKS_START = 1;    
    
    while(!NRF_I2S->EVENTS_TXPTRUPD);    // Wait for the data to be send
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    while(!NRF_I2S->EVENTS_TXPTRUPD);    // Wait for the data to be send
    NRF_I2S->EVENTS_TXPTRUPD = 0; 
    NRF_I2S->TASKS_STOP = 1;
    while(!NRF_I2S->EVENTS_STOPPED);
    NRF_I2S->ENABLE = 0;
}

void sendCommand(uint32_t *commandType, uint32_t *command){
    
    
    /*
     *  Na prvi interrupt pokreni frameTimer. 
     *  Na svaki interrupt (falling edge na Lanc busu) izmjeri vrijeme od zadnjeg eventa
     *  Ako je to vrijeme > 5ms, onda je upravo taj prekid izazvao start bit novog framea
     *  U tom slučaju, kreni s donjim kodom, inaće nemoj ništa slati
     */
    uint8_t cnt = 0;
    
    for(cnt; cnt < 4; cnt++){
        while(!(waitForStartBit()));
        NRF_I2S->TXD.PTR = (uint32_t)commandType;        
        __disable_irq();
        // First or second start bit
        wait_us(60);    // Small delay for first bit after start bit
        sendi2sData();
        __enable_irq();
        i2sFlag = 0;
        
        while(!i2sFlag);        // Wait for new start bit (second byte into frame)
        
        NRF_I2S->TXD.PTR = (uint32_t)command;
        __disable_irq();
        // First or second start bit
        wait_us(60);    // Small delay for first bit after start bit
        sendi2sData();
        i2sFlag = 0;
        __enable_irq();
    }
}

void i2sInit(){
    NRF_I2S->CONFIG.RXEN = 0;       // Disable reception
    NRF_I2S->CONFIG.MCKEN = 1;      // Enable MCK generator
 
    NRF_I2S->CONFIG.MCKFREQ = 0x10000000; // DIV 31
    NRF_I2S->CONFIG.RATIO = 0;          // Ratio = 32x
    
    NRF_I2S->CONFIG.SWIDTH = 0;         // Sample width = 8 bit
    NRF_I2S->CONFIG.ALIGN = 0;          // Alignment = Right
    NRF_I2S->CONFIG.FORMAT = 0;         // Format = I2S
    NRF_I2S->CONFIG.CHANNELS = 0;       // Use stereo
    
    NRF_I2S->PSEL.LRCK = 27;                // LRCK routed to pin 26
    NRF_I2S->PSEL.SDOUT = LANC_COMMAND_PIN; // SDOUT routed to pin 28
    NRF_I2S->PSEL.SCK = 30;                 // SCK routed to pin 30
    NRF_I2S->PSEL.MCK = 0x80000000;         // MCK disconnected
    NRF_I2S->PSEL.SDIN = 0x80000000;        // SDIN disconnected
    
    NRF_I2S->TXD.PTR = (uint32_t)normalCmdAddr;
    NRF_I2S->RXTXD.MAXCNT = MY_BUF_SIZE/4;  // Div with 4 cuz that's number of 32 bit words
}


int main(void){
    alive = LED_OFF;
    
    ble.init(bleInitComplete);
    while (ble.hasInitialized()  == false) { /* spin loop */ }
    ble.gap().startAdvertising();
    
    i2sInit();
    button.fall(i2sReady);
    
    //sendCommand(zoomCmdAddr, zoomInAddr);
    
    connectedLED = LED_OFF;
    testLED = LED_OFF;
    
    while(1){
        ble.waitForEvent();
    }
}