Wednesday 3 June 2015

Seeker V303 YS-S4 serial protocol

V303 uses ZeroUAV YS-S4 fc.
Below is some serial snooping capture from the V303 serial port:



I have not tried to decipher this protocol, but most likely it will be similar to ZeroUAV YS-X4. This could be MAVlink protocol, but customized by ZeroUAV :


YS-X6 serial protocol

20120514
Custom data transmission format
Transmission characteristics: baud rate 115200 8 bits no parity 1 stop bit no hardware flow controlData Format: without stated are the least significant bit firstDownlink:Output ports: On the completion of the power-on initialization, flight control COM1 and COM3 are so agreed output.Transmission order of the beginning of the frame flag, data, parity bit, finished a wait 200ms repeat renewal, or 5 frames per second.

99字节:
1、  the flag at the beginning of frame:(0~3
$STP
2、  GPS data
Aircraft Latitude                            4 bytes            float,单位为度,IEEE浮点格式,低位在前,下同4~7
Aircraft longitude                    4 bytes              float,单位为度  8~11
Target point Longitude           4 bytes              float,单位为度  12~15
Target point latitude       4 bytes          float,单位为度  16~19
The heading angle                     4 bytes              floatradians20~23due north to 0, clockwise is positive
Star Search        1 byte        uchar,将其直接显示即可,单位为颗  (24)
Year                                                1 byte        uchar                              25
Month                                 1 byte        uchar                              26
Day                                                1 byte        uchar                              27
When                                  1 byte        uchar                              28
Points                                 1 byte        uchar                              29
Seconds                               1 byte        uchar                              30

Uploaded total number of waypoints  1 byte       uchar(31)only for automatic navigation
3、  manual rudder format
Rudder 1 byte UCHAR, 100 to 200, unsigned integer, 0 for no input (32)
Aileron 1 byte UCHAR, 100 to 200, unsigned integer, 0 for no input (33)
Elevator 1 byte UCHAR, 100 to 200, unsigned integer, 0 for no input (34)
Throttle 1 byte UCHAR, 100 to 200, unsigned integer, 0 for no input (35)
4、  actual rudder surface state
Rudder 1 byte uchar, 100 ~ 200, unsigned integer (36)
Aileron 1 byte uchar, 100 ~ 200, unsigned integer (37)
Elevator 1 byte uchar, 100 ~ 200, unsigned integer (38)
Throttle 1 byte uchar, 100 ~ 200, unsigned integer (39)
5、  Other
_Y To speed 2 bytes ushort filtering unit for cm / s (40 to 41)
Boot time 2 bytes ushort (42 to 43), seconds
Reserved 1 byte char (44)
Reserved 1 byte uchar, (45)
Distance from the take-off point (high) byte UCHAR, (46), in meters * 256;
PTZ around point radius of 1 byte char (47), in meters
Pressure from 2 bytes int height, the unit decimeter (48 to 49)
GPS velx 2 bytes ushort, unit cm / s (50 to 51)
Distance from the take-off point (low) byte UCHAR, (52), in meters;
Receiver status byte char (53) 0 is open, also receive remote control commands, off, automatic state
Shake coefficient 1 byte uchar (54)
PDOP value of 1 byte uchar, (55)
Vibration coefficient 1 byte uchar (56)
Temperature 1 byte uchar, in degrees, (57)
Right to the acceleration 2 bytes short (58 to 59)
Backward acceleration 2 bytes short (60 to 61)
Pitch angle 4 bytes int (62 to 65) in degrees, Yang is overlooking the negative
Roll angle 4 bytes int (66 to 69) units for the degree of left-right negative
Flight control voltage value 2 bytes ushort (70 to 71) the value / 4096 * 25 voltage value
The downward acceleration of 2 bytes short (72 to 73)
Current task number (to which point) 1 byte uchar, from 0 to 255 unsigned integer (74), from 0 to 1 point
Current control status byte UCHAR, 0x00 manual, 0x01 auto-hover automatic navigation, 0x02, 0x04 to the point, 0x07 to set state, 0x08 gyro cleared 0x0b return landing (75)
Power consumption 2bytes ushort, (76 ~ 77), in mA
Alarm flag 1 byte UCHAR (78) is 1, low voltage, the phone should vibrate, is 0, no alarm;Filtered _D the 1 byte uchar,, velocity (high) units of cm / s * 256 (79)
The rudder position 1 byte UCHAR, (80)Aileron-bit byte UCHAR, (81)
The flipper bit 1 byte uchar (82)
After filtering _X 1 byte uchar speed (high), in units of cm / s * 256 (83)
Set target height 2 bytes, int, in decimeter, (84 ~ 85)
Reserved 3 bytes ushort (86 to 88)
Filtered _D 1 byte uchar, speed (low) to cm / s (89)
Reserved 3 bytes ushort (90 to 92)
Filtered _X 1 byte uchar, speed (low) to cm / s (93)
GPS vely 2 bytes ushort, unit cm / s (94 to 95)
Version No. 2 byte (96 to 97)

6、  End of the frame checksum
Cumulative number of bytes from the header to the previous bytes (98 bytes) unsigned singleuchar (98)


 Below is the Arduino code to decode this data transmitted by the quadcopter (copied from ArducamOSD):

#define SERIALBUFFERSIZE 512
static uint8_t serialBuffer[SERIALBUFFERSIZE]; // this hold the imcoming string from serial O string
static uint8_t readIndex;
static uint8_t receiverIndex = 0;
static uint8_t packetStart = 0;

union u_float_ {
 byte  b[4];
 float floatvalue;
} u_float;

union u_int16_ {
 byte  b[2];
 int16_t intvalue;
} u_int16;

union u_uint16_ {
 byte  b[2];
 uint16_t uintvalue;
} u_uint16;

uint32_t read32() {
  uint32_t t = read16();
  t |= (uint32_t)read16()<<16;
  return t;
}

#define abs_(x) ((x) > 0?(x):-(x))

uint16_t read16() {
  uint16_t t = read8();
  t |= (uint16_t)read8()<<8;
  return t;
}

uint8_t read8()  {
  return serialBuffer[readIndex++];
}

void read_serial(){

    //grabing data
    while(Serial.available() > 0) {
     
        uint8_t c = Serial.read();
        serialBuffer[receiverIndex] = c;
       
        //serialSymb = c;
  
        // Find '$STP' symb
        if (c == 'P' && receiverIndex > 4) {
       
            uint8_t c0 = serialBuffer[receiverIndex-3], c1 = serialBuffer[receiverIndex-2], c2 = serialBuffer[receiverIndex-1], c3 = serialBuffer[receiverIndex];
            if (c0 == '$' && c1 == 'S' && c2 == 'T' && c3 == 'P') {
           
                if (packetStart == 0) {
                  // Start gathering frame
                  packetStart = 1;
                  receiverIndex = 4; // 0..3 in frame == $STP
                  continue;
                } else
                if (packetStart == 1) {
                  // End frame gathering 
                  serialSymb = receiverIndex;
                  serialPackets++;             
                  serialReady = 1;
                  packetStart = 0;
                 
                  // Parse frame
                  // 1) Flight mode
                  base_mode = serialBuffer[75];                 
                  // 2) Voltage
                  u_uint16.b[0] = serialBuffer[70];
                  u_uint16.b[1] = serialBuffer[71];
          //uint16_t battVoltage = serialBuffer[71]*256 + serialBuffer[70];
          osd_vbat_A = 10.0f*(float)u_uint16.uintvalue/2048;
                  // 3) GPS
          osd_satellites_visible = serialBuffer[24];
                  // Latitude
                  u_float.b[0] = serialBuffer[4];
                  u_float.b[1] = serialBuffer[5];
                  u_float.b[2] = serialBuffer[6];
                  u_float.b[3] = serialBuffer[7];
                  osd_lat = u_float.floatvalue;
                  // Longitude
                  u_float.b[0] = serialBuffer[8];
                  u_float.b[1] = serialBuffer[9];
                  u_float.b[2] = serialBuffer[10];
                  u_float.b[3] = serialBuffer[11];
                  osd_lon = u_float.floatvalue;
                  // 4) Altitude, decimeters
                  u_int16.b[0] = serialBuffer[48];
                  u_int16.b[1] = serialBuffer[49];
                  osd_alt = 0.1*(float)u_int16.intvalue;
                  // 5) Home distance
          // Distance from the take-off point (high) byte UCHAR, (46), in meters;
          // Distance from the take-off point (low) byte UCHAR, (52), in meters
          osd_home_distance = serialBuffer[46]*256 + serialBuffer[52];
                  // 6) Speed
                  // GPS velx 2 bytes ushort, unit cm / s (50 to 51)
                  u_int16.b[0] = serialBuffer[50];
                  u_int16.b[1] = serialBuffer[51];
                  float vx = (float)u_int16.intvalue;
                  u_int16.b[0] = serialBuffer[94];
                  u_int16.b[1] = serialBuffer[95];
                  float vy = (float)u_int16.intvalue;
                  osd_gpsspeed = 0.036*sqrt(sq(vx) + sq(vy));
                  // 7) Low battery warning
                  // Alarm flag 1 byte UCHAR (78), 1 - vibrate
                }
            }
        }
       
        receiverIndex++;
        if (receiverIndex >= SERIALBUFFERSIZE-1) {
            receiverIndex = 0;
            packetStart = 0;
        }      
    }
}
 


Installing cheap Banggood gimbal on Vltoys Seeker V303 quadcopter









  1. Gimbal controller uses clone simpleBGC, bought from http://www.banggood.com/FPV-2-Axis-Brushless-Gimbal-With-Controller-For-DJI-Phantom-GoPro-3-p-908068.html
  2. Gimbal setup using SimpleBGC software
  3. Tilt control using channel 8 on the original remote transmitter
  4. Need to pull wire from S2-Y2 for tilt control and connect to the BGC tilt input
  5. Using the original V303 firmware 141045






Thursday 19 February 2015

IoT: Tiva C TM4C123G with ESP8266 and ThingSpeak Talkback to remote update message display from internet

Here is a program I did that interface TI TivaC TM4C123G Launchpad with ESP8266 WiFi module and MAX7219 dot matrix display. Text message can be uploaded through the debug serial port of the TivaC, or remotely from the Thingspeak TalkBack. The BLUE_LED can also be turn on and off remotely from Thingspeak Talkback "TURN_ON" and "TURN_OFF" commands.







The ESP8266 Wifi module is connected to the TivaC second hardware port:
              Serial1.begin(9600);   // pc4- RX1  pc5- TX1

This program also update a chart at Thingspeak with temperature from analog port 2.




Other feature include serial passthrough mode by pressing SW2 button on the TivaC to access terminal mode on ESP8266 as well as for firmware update. Below is the video showing some message sent over from Thingspeak talkback:





And here is the quick and dirty code:

// omarbadar@yahoo Feb 18, 2015
// -wait for serial input and display on LED matrix
// -interface to ESP8266 with AT command firmware
// -Connect to thingspeak server to update temperature and read talkback and display the received message on LED matrix, as well as control BLUE LED using TURN_ON/OFF
// -Pressing PUSH2 button will bring to serial pass through mode where you can debug the ESP8266 directly or reflash
// LED matrix is based on an orginal sketch by Arduino forum member "danigom"
// http://forum.arduino.cc/index.php?action=profile;u=188950 with display rotated 90 deg

#include <LedControl.h>

const int numDevices = 4;      // number of MAX7219s used
const long scrollDelay = 20;   // adjust scrolling speed
const int ledPin =  GREEN_LED;      // the number of the LED pin
unsigned long bufferLong [14] = {0};
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
int ledState = LOW;    
int passtruState = LOW;
long previousMillis = 0;        // will store last time LED was updated
long interval = 10000;
String talkBackCommand; 
String netMsg; 
// convert serial to # str
char buf[16];
String strTemp; // = dtostrf(temp, 4, 1, buf);


LedControl lc=LedControl(23,25,24,numDevices);   // pin PD0, PD2, PD1 on TIVA C

prog_uchar scrollText[] PROGMEM ={"  Net Messaging \0"};


// a function to be executed periodically
void repeatMe() {
    Serial.print("Uptime (s): ");
    Serial.println(millis() / 1000);
    printBufferLong();
    delay(scrollDelay); 

}
// Scroll Message
void scroll() {
    int counter = 0;
    int myChar=0;
    do {
        // read back a char
        //myChar =  inputString[counter];
        myChar =  netMsg[counter];
        if (myChar != 0){
            loadBufferLong(myChar);
        }
        counter++;
    }
    while (myChar != 0);
}


void setup(){
    Serial.begin(9600);
    //HardwareSerial Serial1(4);
    Serial1.begin(9600);   // pc4- RX1  pc5- TX1
    // reserve 200 bytes for the inputString:
    inputString.reserve(400);
    lc.init();
    for (int x=0; x<numDevices; x++){
        lc.shutdown(x,false);       //The MAX72XX is in power-saving mode on startup
        lc.setIntensity(x,3);       // Set the brightness to default value
        lc.clearDisplay(x);         // and clear the display
    }
    scrollMessage(scrollText);
    //Serial.println("testing");
    pinMode(ledPin, OUTPUT);  
    pinMode(RED_LED, OUTPUT);
    pinMode(BLUE_LED, OUTPUT);
    pinMode(PUSH2, INPUT_PULLUP);
    attachInterrupt(PUSH2, passtru, FALLING); // Interrupt is fired whenever button is pressed
    digitalWrite(RED_LED, 0);
}

void loop(){
  // serial pass thru mode to configure ESP8266
  //if(digitalRead(PUSH2)==LOW)
    while(passtruState==HIGH)
    {
     digitalWrite(RED_LED, 1);
     digitalWrite(GREEN_LED, 1);
     if (Serial1.available())
     Serial.write(Serial1.read());
     if (Serial.available())
     Serial1.write(Serial.read());
    } ;
    readTemp();
    updateThingsSpeak();
    checkTalkBack();  
    delay(10000);
    unsigned long currentMillis = millis();
    //scrollMessage(scrollText);
    //scrollFont();
   // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    //scrollMessage("Testing....");
    // clear the string:test
    //inputString = "";
    stringComplete = false;
  }
  
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;  
   
    scroll();
    //Serial.println(inputString);
    //Serial.println("Sending AT+CWLAP...");
    //Serial1.println("AT+CWLAP");
       
   
    delay(200); 
    serialEvent();
        // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, 1);
    delay(200);
    digitalWrite(ledPin, 0);
  }
 
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

prog_uchar font5x7 [] PROGMEM = {      //Numeric Font Matrix (Arranged as 7x font data + 1x kerning data)
    B00000000,    //Space (Char 0x20)
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    6,

    B10000000,    //!
    B10000000,
    B10000000,
    B10000000,
    B00000000,
    B00000000,
    B10000000,
    2,

    B10100000,    //"
    B10100000,
    B10100000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    4,

    B01010000,    //#
    B01010000,
    B11111000,
    B01010000,
    B11111000,
    B01010000,
    B01010000,
    6,

    B00100000,    //$
    B01111000,
    B10100000,
    B01110000,
    B00101000,
    B11110000,
    B00100000,
    6,

    B11000000,    //%
    B11001000,
    B00010000,
    B00100000,
    B01000000,
    B10011000,
    B00011000,
    6,

    B01100000,    //&
    B10010000,
    B10100000,
    B01000000,
    B10101000,
    B10010000,
    B01101000,
    6,

    B11000000,    //'
    B01000000,
    B10000000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    3,

    B00100000,    //(
    B01000000,
    B10000000,
    B10000000,
    B10000000,
    B01000000,
    B00100000,
    4,

    B10000000,    //)
    B01000000,
    B00100000,
    B00100000,
    B00100000,
    B01000000,
    B10000000,
    4,

    B00000000,    //*
    B00100000,
    B10101000,
    B01110000,
    B10101000,
    B00100000,
    B00000000,
    6,

    B00000000,    //+
    B00100000,
    B00100000,
    B11111000,
    B00100000,
    B00100000,
    B00000000,
    6,

    B00000000,    //,
    B00000000,
    B00000000,
    B00000000,
    B11000000,
    B01000000,
    B10000000,
    3,

    B00000000,    //-
    B00000000,
    B11111000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    6,

    B00000000,    //.
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B11000000,
    B11000000,
    3,

    B00000000,    ///
    B00001000,
    B00010000,
    B00100000,
    B01000000,
    B10000000,
    B00000000,
    6,

    B01110000,    //0
    B10001000,
    B10011000,
    B10101000,
    B11001000,
    B10001000,
    B01110000,
    6,

    B01000000,    //1
    B11000000,
    B01000000,
    B01000000,
    B01000000,
    B01000000,
    B11100000,
    4,

    B01110000,    //2
    B10001000,
    B00001000,
    B00010000,
    B00100000,
    B01000000,
    B11111000,
    6,

    B11111000,    //3
    B00010000,
    B00100000,
    B00010000,
    B00001000,
    B10001000,
    B01110000,
    6,

    B00010000,    //4
    B00110000,
    B01010000,
    B10010000,
    B11111000,
    B00010000,
    B00010000,
    6,

    B11111000,    //5
    B10000000,
    B11110000,
    B00001000,
    B00001000,
    B10001000,
    B01110000,
    6,

    B00110000,    //6
    B01000000,
    B10000000,
    B11110000,
    B10001000,
    B10001000,
    B01110000,
    6,

    B11111000,    //7
    B10001000,
    B00001000,
    B00010000,
    B00100000,
    B00100000,
    B00100000,
    6,

    B01110000,    //8
    B10001000,
    B10001000,
    B01110000,
    B10001000,
    B10001000,
    B01110000,
    6,

    B01110000,    //9
    B10001000,
    B10001000,
    B01111000,
    B00001000,
    B00010000,
    B01100000,
    6,

    B00000000,    //:
    B11000000,
    B11000000,
    B00000000,
    B11000000,
    B11000000,
    B00000000,
    3,

    B00000000,    //;
    B11000000,
    B11000000,
    B00000000,
    B11000000,
    B01000000,
    B10000000,
    3,

    B00010000,    //<
    B00100000,
    B01000000,
    B10000000,
    B01000000,
    B00100000,
    B00010000,
    5,

    B00000000,    //=
    B00000000,
    B11111000,
    B00000000,
    B11111000,
    B00000000,
    B00000000,
    6,

    B10000000,    //>
    B01000000,
    B00100000,
    B00010000,
    B00100000,
    B01000000,
    B10000000,
    5,

    B01110000,    //?
    B10001000,
    B00001000,
    B00010000,
    B00100000,
    B00000000,
    B00100000,
    6,

    B01110000,    //@
    B10001000,
    B00001000,
    B01101000,
    B10101000,
    B10101000,
    B01110000,
    6,

    B01110000,    //A
    B10001000,
    B10001000,
    B10001000,
    B11111000,
    B10001000,
    B10001000,
    6,

    B11110000,    //B
    B10001000,
    B10001000,
    B11110000,
    B10001000,
    B10001000,
    B11110000,
    6,

    B01110000,    //C
    B10001000,
    B10000000,
    B10000000,
    B10000000,
    B10001000,
    B01110000,
    6,

    B11100000,    //D
    B10010000,
    B10001000,
    B10001000,
    B10001000,
    B10010000,
    B11100000,
    6,

    B11111000,    //E
    B10000000,
    B10000000,
    B11110000,
    B10000000,
    B10000000,
    B11111000,
    6,

    B11111000,    //F
    B10000000,
    B10000000,
    B11110000,
    B10000000,
    B10000000,
    B10000000,
    6,

    B01110000,    //G
    B10001000,
    B10000000,
    B10111000,
    B10001000,
    B10001000,
    B01111000,
    6,

    B10001000,    //H
    B10001000,
    B10001000,
    B11111000,
    B10001000,
    B10001000,
    B10001000,
    6,

    B11100000,    //I
    B01000000,
    B01000000,
    B01000000,
    B01000000,
    B01000000,
    B11100000,
    4,

    B00111000,    //J
    B00010000,
    B00010000,
    B00010000,
    B00010000,
    B10010000,
    B01100000,
    6,

    B10001000,    //K
    B10010000,
    B10100000,
    B11000000,
    B10100000,
    B10010000,
    B10001000,
    6,

    B10000000,    //L
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B11111000,
    6,

    B10001000,    //M
    B11011000,
    B10101000,
    B10101000,
    B10001000,
    B10001000,
    B10001000,
    6,

    B10001000,    //N
    B10001000,
    B11001000,
    B10101000,
    B10011000,
    B10001000,
    B10001000,
    6,

    B01110000,    //O
    B10001000,
    B10001000,
    B10001000,
    B10001000,
    B10001000,
    B01110000,
    6,

    B11110000,    //P
    B10001000,
    B10001000,
    B11110000,
    B10000000,
    B10000000,
    B10000000,
    6,

    B01110000,    //Q
    B10001000,
    B10001000,
    B10001000,
    B10101000,
    B10010000,
    B01101000,
    6,

    B11110000,    //R
    B10001000,
    B10001000,
    B11110000,
    B10100000,
    B10010000,
    B10001000,
    6,

    B01111000,    //S
    B10000000,
    B10000000,
    B01110000,
    B00001000,
    B00001000,
    B11110000,
    6,

    B11111000,    //T
    B00100000,
    B00100000,
    B00100000,
    B00100000,
    B00100000,
    B00100000,
    6,

    B10001000,    //U
    B10001000,
    B10001000,
    B10001000,
    B10001000,
    B10001000,
    B01110000,
    6,

    B10001000,    //V
    B10001000,
    B10001000,
    B10001000,
    B10001000,
    B01010000,
    B00100000,
    6,

    B10001000,    //W
    B10001000,
    B10001000,
    B10101000,
    B10101000,
    B10101000,
    B01010000,
    6,

    B10001000,    //X
    B10001000,
    B01010000,
    B00100000,
    B01010000,
    B10001000,
    B10001000,
    6,

    B10001000,    //Y
    B10001000,
    B10001000,
    B01010000,
    B00100000,
    B00100000,
    B00100000,
    6,

    B11111000,    //Z
    B00001000,
    B00010000,
    B00100000,
    B01000000,
    B10000000,
    B11111000,
    6,

    B11100000,    //[
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B11100000,
    4,

    B00000000,    //(Backward Slash)
    B10000000,
    B01000000,
    B00100000,
    B00010000,
    B00001000,
    B00000000,
    6,

    B11100000,    //]
    B00100000,
    B00100000,
    B00100000,
    B00100000,
    B00100000,
    B11100000,
    4,

    B00100000,    //^
    B01010000,
    B10001000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    6,

    B00000000,    //_
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B11111000,
    6,

    B10000000,    //`
    B01000000,
    B00100000,
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    4,

    B00000000,    //a
    B00000000,
    B01110000,
    B00001000,
    B01111000,
    B10001000,
    B01111000,
    6,

    B10000000,    //b
    B10000000,
    B10110000,
    B11001000,
    B10001000,
    B10001000,
    B11110000,
    6,

    B00000000,    //c
    B00000000,
    B01110000,
    B10001000,
    B10000000,
    B10001000,
    B01110000,
    6,

    B00001000,    //d
    B00001000,
    B01101000,
    B10011000,
    B10001000,
    B10001000,
    B01111000,
    6,

    B00000000,    //e
    B00000000,
    B01110000,
    B10001000,
    B11111000,
    B10000000,
    B01110000,
    6,

    B00110000,    //f
    B01001000,
    B01000000,
    B11100000,
    B01000000,
    B01000000,
    B01000000,
    6,

    B00000000,    //g
    B01111000,
    B10001000,
    B10001000,
    B01111000,
    B00001000,
    B01110000,
    6,

    B10000000,    //h
    B10000000,
    B10110000,
    B11001000,
    B10001000,
    B10001000,
    B10001000,
    6,

    B01000000,    //i
    B00000000,
    B11000000,
    B01000000,
    B01000000,
    B01000000,
    B11100000,
    4,

    B00010000,    //j
    B00000000,
    B00110000,
    B00010000,
    B00010000,
    B10010000,
    B01100000,
    5,

    B10000000,    //k
    B10000000,
    B10010000,
    B10100000,
    B11000000,
    B10100000,
    B10010000,
    5,

    B11000000,    //l
    B01000000,
    B01000000,
    B01000000,
    B01000000,
    B01000000,
    B11100000,
    4,

    B00000000,    //m
    B00000000,
    B11010000,
    B10101000,
    B10101000,
    B10001000,
    B10001000,
    6,

    B00000000,    //n
    B00000000,
    B10110000,
    B11001000,
    B10001000,
    B10001000,
    B10001000,
    6,

    B00000000,    //o
    B00000000,
    B01110000,
    B10001000,
    B10001000,
    B10001000,
    B01110000,
    6,

    B00000000,    //p
    B00000000,
    B11110000,
    B10001000,
    B11110000,
    B10000000,
    B10000000,
    6,

    B00000000,    //q
    B00000000,
    B01101000,
    B10011000,
    B01111000,
    B00001000,
    B00001000,
    6,

    B00000000,    //r
    B00000000,
    B10110000,
    B11001000,
    B10000000,
    B10000000,
    B10000000,
    6,

    B00000000,    //s
    B00000000,
    B01110000,
    B10000000,
    B01110000,
    B00001000,
    B11110000,
    6,

    B01000000,    //t
    B01000000,
    B11100000,
    B01000000,
    B01000000,
    B01001000,
    B00110000,
    6,

    B00000000,    //u
    B00000000,
    B10001000,
    B10001000,
    B10001000,
    B10011000,
    B01101000,
    6,

    B00000000,    //v
    B00000000,
    B10001000,
    B10001000,
    B10001000,
    B01010000,
    B00100000,
    6,

    B00000000,    //w
    B00000000,
    B10001000,
    B10101000,
    B10101000,
    B10101000,
    B01010000,
    6,

    B00000000,    //x
    B00000000,
    B10001000,
    B01010000,
    B00100000,
    B01010000,
    B10001000,
    6,

    B00000000,    //y
    B00000000,
    B10001000,
    B10001000,
    B01111000,
    B00001000,
    B01110000,
    6,

    B00000000,    //z
    B00000000,
    B11111000,
    B00010000,
    B00100000,
    B01000000,
    B11111000,
    6,

    B00100000,    //{
    B01000000,
    B01000000,
    B10000000,
    B01000000,
    B01000000,
    B00100000,
    4,

    B10000000,    //|
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    B10000000,
    2,

    B10000000,    //}
    B01000000,
    B01000000,
    B00100000,
    B01000000,
    B01000000,
    B10000000,
    4,

    B00000000,    //~
    B00000000,
    B00000000,
    B01101000,
    B10010000,
    B00000000,
    B00000000,
    6,

    B01100000,    // (Char 0x7F)
    B10010000,
    B10010000,
    B01100000,
    B00000000,
    B00000000,
    B00000000,
    5
};

void scrollFont() {
    for (int counter=0x20;counter<0x80;counter++){
        loadBufferLong(counter);
        //delay(30);
    }
}

// Scroll Message
void scrollMessage(prog_uchar * messageString) {
    int counter = 0;
    int myChar=0;
    do {
        // read back a char
        myChar =  pgm_read_byte_near(messageString + counter);
        if (myChar != 0){
            loadBufferLong(myChar);
        }
        counter++;
    }
    while (myChar != 0);
}





// Load character into scroll buffer
void loadBufferLong(int ascii){
    if (ascii >= 0x20 && ascii <=0x7f){
        for (int a=0;a<7;a++){                      // Loop 7 times for a 5x7 font
            unsigned long c = pgm_read_byte_near(font5x7 + ((ascii - 0x20) * 8) + a);     // Index into character table to get row data
            unsigned long x = bufferLong [a*2];     // Load current scroll buffer
            x = x | c;                              // OR the new character onto end of current
            bufferLong [a*2] = x;                   // Store in buffer
        }
        byte count = pgm_read_byte_near(font5x7 +((ascii - 0x20) * 8) + 7);     // Index into character table for kerning data
        for (byte x=0; x<count;x++){
            rotateBufferLong();
            printBufferLong();
            delay(scrollDelay);
        }
    }
}
// Rotate the buffer
void rotateBufferLong(){
    for (int a=0;a<7;a++){                      // Loop 7 times for a 5x7 font
        unsigned long x = bufferLong [a*2];     // Get low buffer entry
        byte b = bitRead(x,31);                 // Copy high order bit that gets lost in rotation
        x = x<<1;                               // Rotate left one bit
        bufferLong [a*2] = x;                   // Store new low buffer
        x = bufferLong [a*2+1];                 // Get high buffer entry
        x = x<<1;                               // Rotate left one bit
        bitWrite(x,0,b);                        // Store saved bit
        bufferLong [a*2+1] = x;                 // Store new high buffer
    }

// Display Buffer on LED matrix
void printBufferLong(){
  for (int a=0;a<7;a++){                    // Loop 7 times for a 5x7 font
    unsigned long x = bufferLong [a*2+1];   // Get high buffer entry
    byte y = x;                             // Mask off first character
    lc.setRow(3,a,y);                       // Send row to relevent MAX7219 chip
    x = bufferLong [a*2];                   // Get low buffer entry
    y = (x>>24);                            // Mask off second character
    lc.setRow(2,a,y);                       // Send row to relevent MAX7219 chip
    y = (x>>16);                            // Mask off third character
    lc.setRow(1,a,y);                       // Send row to relevent MAX7219 chip
    y = (x>>8);                             // Mask off forth character
    lc.setRow(0,a,y);                       // Send row to relevent MAX7219 chip
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  digitalWrite(RED_LED, 1);
  inputString = "";
 /*
  while (Serial1.available()) {
    // get the new byte:
    char inChar = (char)Serial1.read();
    //Serial.print(inChar);
    if (inChar != 0){
         loadBufferLong(inChar);
        
    }
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n')  {
      stringComplete = true;
    }
  
  } */

  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();

    if (inChar != 0){
         loadBufferLong(inChar);
        
    }
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n')  {
      stringComplete = true;
    }

  
  }
  digitalWrite(RED_LED, 0);
}


void passtru()
  {
  delay(20); 
  if (passtruState == LOW)
    {
      passtruState = HIGH;
      digitalWrite(RED_LED, 1);
      digitalWrite(GREEN_LED, 1);
    }
  else
     {
      passtruState = LOW;
      digitalWrite(RED_LED, 0);
      digitalWrite(GREEN_LED, 0);
    }
   }

void updateThingsSpeak()
{
  // replace with your channel's thingspeak API key
  String apiKey = "XXXXXXXXXXXXX";  // ch 22186  https://thingspeak.com/channels/22186

  // TCP connection
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += "184.106.153.149"; // "184.106.153.149"
  cmd += "\",80";
  Serial1.println(cmd);
  Serial.println(cmd);
 
  if(Serial1.find("Error")){
    Serial.println("AT+CIPSTART error");
    return;
  }
 
  // prepare GET string
  String getStr = "GET /update?api_key=";
  getStr += apiKey;
  getStr +="&field1=";
  getStr += String(strTemp);
  getStr += "\r\n\r\n";

  // send data length
  cmd = "AT+CIPSEND=";
  cmd += String(getStr.length());
  Serial1.println(cmd);
  Serial.println(cmd);
 
  if(Serial1.find(">")){
    Serial1.print(getStr);
    Serial.println(getStr);
  }
  else{
    Serial1.println("AT+CIPCLOSE");
    // alert user
    Serial.println("AT+CIPCLOSE");
  }
 
}

void checkTalkBack()
{
 
String talkBackAPIKey = "ZZZZZZZZZZZ"; // Name:     TivaC_LED_matrix  TalkBack ID:     1234
String talkBackID = "1234";


  char charIn;
  // TCP connection
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += "184.106.153.149"; // "184.106.153.149"
  cmd += "\",80";
  delay(1000);
  Serial1.println(cmd);
  Serial.println(cmd);
 
  if(Serial1.find("Error")){
    Serial.println("AT+CIPSTART error");
    return;
  }
 
  // prepare GET string

  String getStr = "GET https://api.thingspeak.com/talkbacks/" + talkBackID + "/commands/execute?api_key=" + talkBackAPIKey;
 
  ///getStr += apiKey;
  ///getStr +="&field1=";
  ///getStr += String(strTemp);
  getStr += "\r\n\r\n";

  // send data length
  cmd = "AT+CIPSEND=";
  cmd += String(getStr.length());
  Serial1.println(cmd);
  Serial.println(cmd);
 
  if(Serial1.find(">")){
    Serial1.print(getStr);
    Serial.println(getStr);
  }
  else{
    Serial1.println("AT+CIPCLOSE");
    // alert user
    Serial.println("AT+CIPCLOSE");
  }
  Serial.print("wait...");
  delay(1000);
  talkBackCommand="";
  while (Serial1.available()) {

  
      charIn = Serial1.read();
      Serial.print(charIn);
      talkBackCommand += charIn;
   
   }

  Serial.println(talkBackCommand);

    // Turn On/Off the On-board LED
    if (find_text("TURN_ON",talkBackCommand) > 0 )
    {
        Serial.println(talkBackCommand);
        digitalWrite(BLUE_LED, HIGH);
    }
    else if (find_text("TURN_OFF",talkBackCommand) > 0)
    {
        Serial.println(talkBackCommand);
        digitalWrite(BLUE_LED, LOW);
    }
    else if (find_text("+IPD",talkBackCommand) > 0)
        {
         inputString = talkBackCommand.substring(find_text("+IPD",talkBackCommand));
         if (find_text("OK",inputString) > 0) netMsg = inputString.substring(8,find_text("OK"  ,inputString));
         inputString=netMsg;
         if (find_text("OK",inputString) > 0) netMsg = inputString.substring(0,find_text("OK"  ,inputString));
         Serial.print("Length of netMsg ");
         Serial.println(find_text("OK"  ,inputString));
        }
    Serial1.flush();
    delay(1000);
}


int find_text(String needle, String haystack) {
  int foundpos = -1;
  for (int i = 0; (i < haystack.length() - needle.length()); i++) {
    if (haystack.substring(i,needle.length()+i) == needle) {
      foundpos = i;
    }
  }
  return foundpos;
}

void readTemp()
{
  // read the value from LM35.
  // read 10 values for averaging.
  int val = 0;
  for(int i = 0; i < 10; i++) {
      val += analogRead(2);  
      delay(100);
  }

  // convert to temp:
  // temp value is in 0-1023 range
  // LM35 outputs 10mV/degree C. ie, 1 Volt => 100 degrees C
  // So Temp = (avg_val/1023)*5 Volts * 100 degrees/Volt
  float temp = val*50.0f/1023.0f;
  strTemp = dtostrf(temp, 4, 1, buf);
 
  Serial.println(strTemp); 
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////