/* This sketch requires a TellyMate. It displays a simple wave display. I'm afraid that I've not had time to tidy it up. It works hard to only send the changed data to the screen. Slowly changing graphs work rather fluidly. Full-amplitude, high frequency waves get very chuggy. It's essentially a set of 50 bar graphs. 25 for the left-hand side and 25 for the right-hand side. Each bar graph is responsible for drawing itself, and maintains its previous state, so can determine exactly which parts need redrawing (if at all). */ #define BAUD_RATE 57600 #define CHAR_ESC "\x1B" #define CHAR_DLE "\x10" class BarV { private: int s_iSegment ; public: BarV( void ): s_iSegment(10000){} ; private: void _repeatchar( const char c, const byte count, const byte pos , const byte startpos, const byte endpos ) { byte p = pos ; for( byte i = 0 ; i < count ; i++ ) { if (p++ >= startpos) tm_printchar( c ) ; if (p > endpos) return ; } } void _drawbar( const byte row, const byte col, char cBefore, char cAfter, const char *strBarBase, const byte iBaseLen, const byte iBarLen, const float fMin, const float fMax, const float fValue, const boolean bBlankStart, const boolean bBlankEnd, const boolean bIsSlider ) { const int iSegments_calc = (iBaseLen * iBarLen) + (bBlankStart?1:0) + (bBlankEnd?1:0) ; const int iSegments_disp = (iBaseLen * iBarLen) + (bBlankStart?1:0) ; const float fFraction = (fValue - fMin) / (fMax - fMin) ; const int iSegment = floor( iSegments_calc * fFraction ) - (bBlankStart?1:0) ; const signed char iBarPos = iSegment / iBaseLen ; const signed char iBarSub = iSegment % iBaseLen ; const signed char iBarPos_old = s_iSegment / iBaseLen ; const signed char iBarSub_old = s_iSegment % iBaseLen ; byte pos = 0; if ((iBarPos == iBarPos_old) && (iBarSub == iBarSub_old)) return ; // nothing to do! const signed char startpos = (s_iSegment >= 10000)?0:max(min( iBarPos, iBarPos_old),0) ; const signed char endpos = (s_iSegment >= 10000)?iBarLen:max(max( iBarPos, iBarPos_old),0) ; s_iSegment = iSegment ; tm_cursor_move( row, col + startpos ) ; if (iSegment < 0) { // out-of-bounds, 'before'-side. if (bIsSlider) { if (pos++ >= startpos) tm_printchar( strBarBase[0] ) ; _repeatchar( cAfter, iBarLen - 1, pos, startpos, endpos ) ; } else { _repeatchar( cAfter, iBarLen, pos, startpos, endpos ) ; } return ; } if (iSegment >= iSegments_disp) { // out-of-bounds, 'after'-side. if (bIsSlider) { _repeatchar( cBefore, iBarLen - 1, pos, startpos, endpos) ; pos += iBarLen - 1 ; if (pos > endpos) return ; if (pos++ >= startpos) tm_printchar( strBarBase[iBaseLen - 1] ) ; } else { _repeatchar( cBefore, iBarLen, pos, startpos, endpos) ; } return ; } _repeatchar( cBefore, iBarPos, pos, startpos, endpos ) ; pos+= iBarPos ; if (pos > endpos) return ; if (pos++ >= startpos) tm_printchar( strBarBase[iBarSub] ) ; if (pos > endpos) return ; _repeatchar( cAfter, iBarLen - iBarPos - 1, pos, startpos, endpos ) ; pos += iBarLen - iBarPos - 1 ; if (pos > endpos) return ; } public: void Draw(const byte row, const byte col, const char cBefore, const char cAfter, const char *strBarBase, const byte iBaseLen, const byte iBarLen, const float fMin, const float fMax, const float fValue, const boolean bBlankStart, const boolean bBlankEnd, const boolean bIsSlider) { s_iSegment = 10000 ; Update( row, col, cBefore, cAfter, strBarBase, iBaseLen, iBarLen, fMin, fMax, fValue, bBlankStart, bBlankEnd, bIsSlider ) ; } void Update( const byte row, const byte col, const char cBefore, const char cAfter, const char *strBarBase, const byte iBaseLen, const byte iBarLen, const float fMin, const float fMax, const float fValue, const boolean bBlankStart, const boolean bBlankEnd, const boolean bIsSlider) { _drawbar( row, col, cBefore, cAfter, strBarBase, iBaseLen, iBarLen, fMin, fMax, fValue, bBlankStart, bBlankEnd, bIsSlider ) ; } }; void tm_cursor_move( uint8_t row , uint8_t col ) { // Yrc Serial.print( CHAR_ESC "Y" ) ; Serial.print((unsigned char)(32 + row)) ; Serial.print((unsigned char)(32 + col)) ; } void tm_printchar( char c ) { if ( c < 32 ) Serial.print( CHAR_DLE ) ; Serial.print( c ) ; } double s_base = 0; BarV bars_pos[25] = { BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV() }; BarV bars_neg[25] = { BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(),BarV(), BarV() }; char *strLeftFill = "\xdd\xdb" ; char *strRightFill = "\xdb\xde" ; void setup( void ) { Serial.begin( BAUD_RATE ) ; // enable transmit sequence: Serial.print( CHAR_ESC ) ; for( byte i = 0 ; i < 4 ; i++ ){ Serial.print( '~' ) ; } Serial.print( CHAR_ESC "E" ) ; delay(200); Serial.flush(); /* for ( byte row = 0 ; row < 25 ; row++ ) { tm_cursor_move( row , 0 ) ; Serial.print( CHAR_ESC "_7" ) ; } */ Serial.print( CHAR_ESC "f" ) ; for ( byte row = 0 ; row < 25 ; row++ ) { double d = fn( s_base , row ) ; // double d = sin( ((double)(0 + col) * 2 * PI) / 100 ) * sin( ((double)(0 + col) * 2 * PI) / 35.0 ); bars_neg[row].Draw( row, 0, 32, 219, strRightFill, 2, 19, -1,0,d,0,0,0 ) ; bars_pos[row].Draw( row, 19,219, 32, strLeftFill, 2, 19, 0,1,d,0,0,0 ) ; } } double fn( double base, byte col ) { // return ((2 * sin( ((double)(s_base + col) * 2 * PI) / 35.0 ) * sin( ((double)(s_base + col) * 2 * PI) / 35.0 ) * sin( ((double)(s_base + col) * 2 * PI) / 35.0 ) * sin( ((double)(s_base + col) * 2 * PI) / 35.0 )) - 1); // return sin( ((double)(s_base + col) * 2 * PI) / 100 ) * sin( ((double)(s_base + col) * 2 * PI) / 35.0 ); return sin( (((double)(s_base + col) + (30 * sin(s_base / 16.5))) * 2 * PI) / 100 ) * sin( ((double)(s_base + col) * 2 * PI) / 35.0 ); } void loop( void ) { s_base += 0.6 + (0.32 * sin( s_base / 10 )); // s_base += 0.15; for ( byte row = 0 ; row < 25 ; row++ ) { double d = fn( s_base , row ) ; bars_neg[row].Update( row, 0, 32, 219, strRightFill, 2, 19, -1,0, d,0,0,0 ) ; bars_pos[row].Update( row, 19, 219,32, strLeftFill, 2, 19, 0 ,1, d,0,0,0 ) ; } }