Desktop Station gateway software for mbed

Dependents:   DSGatewayMBED_Nucleo DSGatewayMBED_Nucleo_Step128

This library provides to control DCC and Marklin Motorola 2 locomtoives and turnouts via DCC/MM2 Shield. Please check our wiki site(http://desktopstation.net/wiki/).

DSGatewayMBED.cpp

Committer:
yaasan
Date:
2015-01-23
Revision:
1:39249e22e9f5
Parent:
0:96eb8cc345dc

File content as of revision 1:39249e22e9f5:

/*********************************************************************
 * Desktop Station Gateway Library for mbed platform
 *
 * Copyright (C) 2015 Yaasan
 *
 */

#include "DSGatewayMBED.h"
#include "mbed.h"

SPI spiDS(SPI_MOSI, SPI_MISO, SPI_SCK);
DigitalOut cs(PB_6);

DSGatewayLib::DSGatewayLib()
{
    
    poweron = false;
    
}

void DSGatewayLib::begin()
{
  /* Open SPI */

  /* SPI mode is default( 8bit, mode 0, 1MHz) */
  //spiDS.format(8, 0);
  //spiDS.frequency(1000000);
    cs = 1;
}


DSGatewayLib::~DSGatewayLib()
{
  
  SetPower(false);

}

bool DSGatewayLib::IsPower()
{
    
    return poweron;
    
}


void DSGatewayLib::clearMessage(unsigned char *inPackets)
{
    for( int i = 0; i < SIZE_PACKET; i++)
    {
        inPackets[i] = 0;
    } 
}

bool DSGatewayLib::sendMessage(unsigned char *inPackets)
{
    byte aReceived[SIZE_PACKET] = {0,0,0,0,0,0,0,0};
    int i;

    cs = 0;
    
    for( i = 0; i < SIZE_PACKET; i++)
    {
       aReceived[i] = reverseByte(spiDS.write(reverseByte(inPackets[i])));
    }
    
    cs = 1;
    
    
    /* 遅延 */
    wait_ms(5);
   
    /* Check for receiving */
    if((aReceived[1] & 0xF0) == CMD_OK)
    {
        return true;    
    }
    else if((aReceived[1] & 0xF0) == CMD_WAIT)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool DSGatewayLib::exchangeMessage(unsigned char *inPackets, word timeout)
{
    //unsigned char aTemp[SIZE_PACKET];

    bool aReturnOk = sendMessage(inPackets);
    
    /*
    unsigned long aTime = millis();

    // response;

    while ((millis() < aTime + timeout) || (!aReturnOk)) {
        aTemp[0] = CMD_WAIT | 0b0010;
        aTemp[1] = aTemp[0];
        
        delay(20);
        
        if (sendMessage(aTemp) == true) {
            return true;
        }
    }

    if (DEBUG && !aReturnOk) {
        Serial.println(F("!!! Communication Error(Timeout, Command etc)"));
    }
    */
    
    return aReturnOk;
}


bool DSGatewayLib::SetPower(byte power)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    if (power == 1) {
        aPacktes[0] = CMD_PWR_ON | 0x02;
        aPacktes[1] = aPacktes[0];//CRC
        poweron = true;

    }
    else
    {
        aPacktes[0] = CMD_PWR_OFF | 0x02;
        aPacktes[1] = aPacktes[0];//CRC
        poweron = false;
    }

    return exchangeMessage(aPacktes, TIME_REPLY);
}

bool DSGatewayLib::SetPowerEx(byte power)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    if (power == 1) {
        aPacktes[0] = CMD_PWR_ON | 0x03;
        aPacktes[1] = 3;//Extend command (DCC128 and MM2-28step)
        aPacktes[2] = generateCRC(aPacktes, 2);

    }
    else
    {
        aPacktes[0] = CMD_PWR_OFF | 0x02;
        aPacktes[1] = aPacktes[0];//CRC
    }
    


    return exchangeMessage(aPacktes, TIME_REPLY);
}

bool DSGatewayLib::SetLocoSpeed(word address, int inSpeed)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_SPEED | 0x06;
    aPacktes[1] = lowByte(address);
    aPacktes[2] = highByte(address);
    aPacktes[3] = lowByte(inSpeed);
    aPacktes[4] = highByte(inSpeed);
    aPacktes[5] = generateCRC(aPacktes, 5);

    return exchangeMessage(aPacktes, TIME_REPLY);
}


bool DSGatewayLib::SetLocoSpeedEx(word address, int inSpeed, int inProtcol)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_SPEED | 0x07;
    aPacktes[1] = lowByte(address);
    aPacktes[2] = highByte(address);
    aPacktes[3] = lowByte(inSpeed);
    aPacktes[4] = highByte(inSpeed);
    aPacktes[5] = inProtcol;
    aPacktes[6] = generateCRC(aPacktes, 6);

    return exchangeMessage(aPacktes, TIME_REPLY);
} 

bool DSGatewayLib::SetLocoFunction(word address, unsigned char inFunction, unsigned char inPower)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_FUNCTION | 0x06;
    aPacktes[1] = lowByte(address);
    aPacktes[2] = highByte(address);
    aPacktes[3] = inFunction + 1; //1はじまり
    aPacktes[4] = inPower;
    aPacktes[5] = generateCRC(aPacktes, 5);

    return exchangeMessage(aPacktes, TIME_REPLY);
}


bool DSGatewayLib::SetLocoDirection(word address, unsigned char inDirection)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_DIRECTION | 0x05;
    aPacktes[1] = lowByte(address);
    aPacktes[2] = highByte(address);
    aPacktes[3] = inDirection - 1;// FWD 1->0, REV:2->1
    aPacktes[4] = generateCRC(aPacktes, 4);

    return exchangeMessage(aPacktes, TIME_REPLY);
}

/*
bool DSGatewayLib::SetTurnout(word address, bool straight)
{
    byte aSwitch = straight == true ? (byte)1 : (byte)0;
    
    return SetTurnout(address, aSwitch);
}*/

bool DSGatewayLib::SetTurnout(word address, byte inSwitch)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_ACCESSORY | 0x06;
    aPacktes[1] = lowByte(address);
    aPacktes[2] = highByte(address);
    aPacktes[3] = 0x00; // position
    aPacktes[4] = convertAcc_MMDCC(address, inSwitch);// 0: Straight, 1: diverging from DS 1:straight, 0: diverging
    aPacktes[5] = generateCRC(aPacktes, 5);

    return exchangeMessage(aPacktes, TIME_REPLY);
}

byte DSGatewayLib::convertAcc_MMDCC(word address, byte inSwitch)
{
    byte aReturn = inSwitch;
    
    switch( GetLocIDProtocol(address >> 8))
    {
    case ADDR_ACC_MM2:
        /* 0:Straight, 1: diverging */
        aReturn = (inSwitch == 0) ? 1 : 0;
        break;
        
    case ADDR_ACC_DCC:
        /* 1:Straight, 0: diverging */
        aReturn = inSwitch;
        break;
        
    default:
        aReturn = inSwitch;
        break;
    }
    
    return aReturn;
    
}

word DSGatewayLib::GetLocIDProtocol(byte address)
{
    if( address < 0x04)
    {
            return ADDR_MM2;
    }
    else if( (address >= 0x30) && (address <= 0x33))
    {
            return ADDR_ACC_MM2;
    }
    else if( (address >= 0x38) && (address <= 0x3F))
    {
            return ADDR_ACC_DCC;
    }
    else if( (address >= 0x40) && (address <= 0x70))
    {
            return ADDR_MFX;
    }
    else if( (address >= 0xC0) && (address <= 0xFF))
    {
            return ADDR_DCC;
    }
    else
    {
        return 0;
    }
}

bool DSGatewayLib::WriteConfig(word address, word number, byte value)
{
    unsigned char aPacktes[SIZE_PACKET];
    
    word aOffsetCVNo;
    
    if( address >= ADDR_DCC)
    {
        aOffsetCVNo = number;
    }
    else
    {
        aOffsetCVNo = number | 0x8000;
    }

    clearMessage(aPacktes);

    aPacktes[0] = CMD_CVWRITE | 0x05;
    aPacktes[1] = lowByte(aOffsetCVNo);
    aPacktes[2] = highByte(aOffsetCVNo);
    aPacktes[3] = value; 
    aPacktes[4] = generateCRC(aPacktes, 4);

    return exchangeMessage(aPacktes, TIME_REPLY);
}

bool DSGatewayLib::ReadConfig(word address, word number, byte *value)
{
    unsigned char aPacktes[SIZE_PACKET];

    clearMessage(aPacktes);

    aPacktes[0] = CMD_CVREAD || 0x04;
    aPacktes[1] = lowByte(number);
    aPacktes[2] = highByte(number);
    aPacktes[3] = generateCRC(aPacktes, 3);
    
    *value = 0;

    return exchangeMessage(aPacktes, TIME_REPLY);
}


unsigned char DSGatewayLib::generateCRC(unsigned char *inPackets, unsigned char inLen)
{
    unsigned char aCRC = inPackets[0];

    for( int i = 1; i < inLen; i++)
    {
        aCRC = aCRC ^ inPackets[i];
    }
    
    return aCRC;

}

byte lowByte(short int low) {
    byte bytelow = 0;
    bytelow = (low & 0xFF);
    return bytelow;
}

byte highByte(short int high) {
    byte bytehigh = 0;
    bytehigh = ((high >> 8) & 0xFF);
    return bytehigh;
}

unsigned char reverseByte(unsigned char inByte)
{
    
    unsigned char aTemp = 0;
    
    for( int i = 0; i < 8; i++)
    {
        aTemp = aTemp | (((inByte >> i) & 0x01) << (7 - i));
    }   
    
    return aTemp;
    
}