libraries / Mitov / Mitov_MaximLedControl.hon commit Added link to project report (97a3ba0)
   1////////////////////////////////////////////////////////////////////////////////
   2//                                                                            //
   3//     This software is supplied under the terms of a license agreement or    //
   4//     nondisclosure agreement with Mitov Software and may not be copied      //
   5//     or disclosed except in accordance with the terms of that agreement.    //
   6//         Copyright(c) 2002-2016 Mitov Software. All Rights Reserved.        //
   7//                                                                            //
   8////////////////////////////////////////////////////////////////////////////////
   9
  10#ifndef _MITOV_MAXIM_LED_CONTROL_h
  11#define _MITOV_MAXIM_LED_CONTROL_h
  12
  13#include <Mitov.h>
  14#include <Mitov_Basic_SPI.h>
  15//#include <Mitov_7Segment_Common.h>
  16
  17namespace Mitov
  18{
  19        const byte C_MaximSegments[16] =
  20        {
  21                0b1111110,  // = 0
  22                0b0110000,  // = 1
  23                0b1101101,  // = 2
  24                0b1111001,  // = 3
  25                0b0110011,  // = 4
  26                0b1011011,  // = 5
  27                0b1011111,  // = 6
  28                0b1110000,  // = 7
  29                0b1111111,  // = 8
  30                0b1111011,  // = 9
  31                0b1110111,  // = A
  32                0b0011111,  // = B
  33                0b0001101,  // = C
  34                0b0111101,  // = D
  35                0b1001111,  // = E
  36                0b1000111   // = F
  37        };
  38//---------------------------------------------------------------------------
  39        const byte C_MaximDecimalPoint[2] =
  40        {
  41                0b00000000,
  42                0b10000000
  43        };
  44//---------------------------------------------------------------------------
  45        class MaximLedCommonGroup;
  46//---------------------------------------------------------------------------
  47        class MaximLedGroupOwner
  48        {
  49        public:
  50                Mitov::SimpleObjectList<MaximLedCommonGroup*>   FPixelGroups;
  51
  52        public:
  53                virtual void SetPixelValue( int AIndex, bool AValue ) = 0;
  54                virtual bool GetPixelValue( int AIndex ) = 0;
  55
  56        };
  57//---------------------------------------------------------------------------
  58        class MaximLedCommonGroup : public OpenWire::Component
  59        {
  60        protected:
  61                MaximLedGroupOwner &FOwner;
  62
  63                bool    Enabled = true;
  64
  65        public:
  66                void SetEnabled( bool AValue )
  67                {
  68                        if( Enabled == AValue )
  69                                return;
  70
  71                        Enabled = AValue;
  72                        UpdateDisplay();
  73                }
  74
  75        public:
  76                virtual void StartPixels( int &AStartPixel ) = 0;
  77                virtual void PixelsClock( unsigned long currentMicros )
  78                {
  79                }
  80
  81        protected:
  82                virtual void UpdateDisplay() {}
  83
  84        public:
  85                MaximLedCommonGroup( MaximLedGroupOwner &AOwner ) :
  86                        FOwner( AOwner )
  87                {
  88                        FOwner.FPixelGroups.push_back( this );
  89                }
  90        };
  91//---------------------------------------------------------------------------
  92        template<int COUNT_CONTROLLERS> class MaximLedController : public Mitov::Basic_SPI, public Mitov::ClockingSupport, public Mitov::MaximLedGroupOwner
  93        {
  94                typedef Mitov::Basic_SPI inherited;
  95
  96        protected:
  97                static const    byte OP_DIGIT0 = 1;
  98                static const    byte OP_DECODEMODE = 9;
  99                static const    byte OP_INTENSITY = 10;
 100                static const    byte OP_SCANLIMIT = 11;
 101                static const    byte OP_SHUTDOWN = 12;
 102                static const    byte OP_DISPLAYTEST = 15;
 103
 104        protected:
 105//              int             FNumDevices;
 106
 107                byte    FRegistersCurrent[ COUNT_CONTROLLERS * 8 ];
 108                byte    FRegisters[ COUNT_CONTROLLERS * 8 ];
 109
 110                bool    FModified = false;
 111
 112        public:
 113                float   Intensity = 1.0f;
 114
 115        protected:
 116                void SetIntensity( float AValue )
 117                {
 118                        if( Intensity == AValue )
 119                                return;
 120
 121                        Intensity = AValue;
 122                        UpdateIntensity();
 123                }
 124
 125                void SetEnabled( bool AValue )
 126                {
 127                        if( Enabled == AValue )
 128                                return;
 129
 130                        Enabled = AValue;
 131                        UpdateShutDown();
 132                }
 133
 134        public:
 135                virtual void SetPixelValue( int AIndex, bool AValue )
 136                {
 137                        if( AValue )
 138                                FRegisters[ AIndex / 8 ] |= 1 << ( AIndex & 7 );
 139
 140                        else
 141                                FRegisters[ AIndex / 8 ] &= ~( 1 << ( AIndex & 7 ));
 142
 143                        FModified = true;
 144                }
 145
 146                virtual bool GetPixelValue( int AIndex )
 147                {
 148                        return FRegisters[ AIndex / 8 ] & ( 1 << ( AIndex & 7 ));
 149                }
 150
 151        protected:
 152                void spiTransferAll( byte opcode, byte data )
 153                {
 154                        //enable the line 
 155                        ChipSelectOutputPin.SendValue( false );
 156                        //Now shift out the data 
 157
 158                        for(int i = 0; i < COUNT_CONTROLLERS; ++i )
 159                        {    
 160                                FSPI.transfer( opcode );
 161                                FSPI.transfer( data );
 162                        }
 163    
 164                        //latch the data onto the display
 165                        ChipSelectOutputPin.SendValue( true );
 166                }
 167
 168/*
 169                void spiTransfer( int addr, byte opcode, byte data )
 170                {
 171                        //enable the line 
 172                        ChipSelectOutputPin.SendValue( false );
 173                        //Now shift out the data 
 174
 175                        for(int i = 1; i < COUNT_CONTROLLERS; ++i )
 176                                FSPI.transfer16( 0 ); // Skip one chip
 177      
 178                        FSPI.transfer( opcode );
 179                        FSPI.transfer( data );
 180    
 181                        //latch the data onto the display
 182                        ChipSelectOutputPin.SendValue( true );
 183                }    
 184*/
 185        protected:
 186                inline void UpdateIntensity()
 187                {
 188                        spiTransferAll( OP_INTENSITY, Intensity * 15 + 0.5 );
 189                }
 190
 191                inline void UpdateShutDown()
 192                {
 193                        spiTransferAll( OP_SHUTDOWN, Enabled );
 194                }
 195
 196                void UpdatePixels()
 197                {
 198                        uint16_t ABuffer[ COUNT_CONTROLLERS ];
 199                        FModified = false;
 200
 201                        for(;;)
 202                        {
 203                                bool HasChange = false;
 204                                for( int AControllerIndex = 0; AControllerIndex < COUNT_CONTROLLERS; ++AControllerIndex )
 205                                {
 206                                        ABuffer[ AControllerIndex ] = 0;
 207                                        for( int j = 0; j < 8; ++j )
 208                                        {
 209                                                int ARegIndex = AControllerIndex * 8 + j;
 210                                                uint16_t ANewRegValue = FRegisters[ ARegIndex ];
 211                                                if( FRegistersCurrent[ ARegIndex ] != ANewRegValue )
 212                                                {
 213                                                        FRegistersCurrent[ ARegIndex ] = ANewRegValue;
 214                                                        ABuffer[ AControllerIndex ] = ( ANewRegValue << 8 ) | ( OP_DIGIT0 + j );
 215                                                        HasChange = true;
 216                                                        break;
 217                                                }
 218                                        }
 219                                }
 220
 221                                if( !HasChange )
 222                                        break;
 223
 224                                //enable the line 
 225                                ChipSelectOutputPin.SendValue( false );
 226                                FSPI.transfer( ABuffer, COUNT_CONTROLLERS * 2 );
 227
 228                                //latch the data onto the display
 229                                ChipSelectOutputPin.SendValue( true );
 230                        }
 231                }
 232
 233        protected:
 234                virtual void SystemInit()
 235                {
 236                        int AStartPixel = 0;
 237                        for( int i = 0; i < FPixelGroups.size(); ++i )
 238                                FPixelGroups[ i ]->StartPixels( AStartPixel );  
 239
 240//                      FNumDevices = ( AStartPixel + 63 ) / 64;
 241
 242//                      FRegisters.SetCount( FNumDevices * 8, 0 );
 243//                      FRegistersCurrent.SetCount( FNumDevices * 8, 0 );
 244
 245                        spiTransferAll( OP_DISPLAYTEST, 0 );
 246                        spiTransferAll( OP_SCANLIMIT, 7 );
 247                        spiTransferAll( OP_DECODEMODE, 0 );
 248
 249                        UpdateShutDown();
 250                        UpdateIntensity();
 251
 252//                      if( FModified )
 253
 254
 255                        for( int i = 0; i < COUNT_CONTROLLERS * 8; ++i )
 256                                FRegistersCurrent[ i ] = FRegisters[ i ] + 1;
 257
 258                        UpdatePixels();
 259
 260//                      spiTransferAll( OP_DIGIT0, 255 );
 261                        inherited::SystemInit();
 262                }
 263
 264                virtual void SystemLoopBegin( unsigned long currentMicros )
 265                {
 266                        for( int i = 0; i < FPixelGroups.size(); ++i )
 267                                FPixelGroups[ i ]->PixelsClock( currentMicros );
 268
 269                        inherited::SystemLoopBegin( currentMicros );
 270                }
 271
 272                virtual void SystemLoopEnd()
 273                {
 274                        if( FModified )
 275                                if( ! ClockInputPin.IsConnected())
 276                                        UpdatePixels();
 277
 278                        inherited::SystemLoopEnd();
 279                }
 280
 281        protected:
 282                virtual void DoClockReceive( void * )
 283                {
 284                        if( FModified )
 285                                UpdatePixels();
 286                }
 287
 288        public:
 289                MaximLedController( BasicSPI &ASPI ) :
 290                        inherited( ASPI )
 291                {
 292                        for( int i = 0; i < COUNT_CONTROLLERS * 8; ++i )
 293                                FRegisters[ i ] = 0;
 294                }
 295        };
 296//---------------------------------------------------------------------------
 297        class MaximLedBasicGroup : public MaximLedCommonGroup
 298        {
 299                typedef Mitov::MaximLedCommonGroup inherited;
 300
 301        public:
 302                int             CountPixels = 64;
 303
 304        public:
 305                virtual void StartPixels( int &AStartPixel )
 306                {
 307//                      inherited::StartPixels( AStartPixel );
 308                        AStartPixel += CountPixels;
 309                }
 310
 311        public:
 312                using inherited::inherited;
 313
 314        };
 315//---------------------------------------------------------------------------
 316        class MaximLedBasicInitialValueGroup : public MaximLedBasicGroup
 317        {
 318                typedef Mitov::MaximLedBasicGroup inherited;
 319
 320        public:
 321                bool    InitialValue = false;
 322
 323        public:
 324                using inherited::inherited;
 325
 326        };
 327//---------------------------------------------------------------------------
 328        class MaximLedGroupBasicBooleanPixels : public MaximLedBasicInitialValueGroup
 329        {
 330                typedef Mitov::MaximLedBasicInitialValueGroup inherited;
 331
 332        protected:
 333                class PixelVlaueSinkPin : public OpenWire::VlaueSinkPin<bool>
 334                {
 335                        typedef OpenWire::VlaueSinkPin<bool> inherited;
 336
 337                public:
 338                        MaximLedGroupBasicBooleanPixels *FOwner;
 339                        int                                                              FIndex;
 340
 341                public:
 342                        virtual void Receive( void *_Data )
 343                        {
 344                                bool AValue = *(bool *)_Data;
 345                                if( AValue != Value )
 346                                        if( FOwner->Enabled )
 347                                                FOwner->FOwner.SetPixelValue( FIndex, AValue );
 348
 349                                inherited::Receive( _Data );
 350                        }
 351                };
 352
 353        protected:
 354                virtual void UpdateDisplay()
 355                {
 356                        for( int i = 0; i < InputPins.size(); ++i )
 357                        {
 358                                if( Enabled )
 359                                        FOwner.SetPixelValue( InputPins[ i ].FIndex, InputPins[ i ].Value );
 360
 361                                else
 362                                        FOwner.SetPixelValue( InputPins[ i ].FIndex, false );
 363                        }
 364                }
 365
 366        public:
 367                Mitov::SimpleList<PixelVlaueSinkPin> InputPins;
 368
 369        public:
 370                using inherited::inherited;
 371
 372        };
 373//---------------------------------------------------------------------------
 374        class MaximLedGroup : public MaximLedGroupBasicBooleanPixels
 375        {
 376                typedef Mitov::MaximLedGroupBasicBooleanPixels inherited;
 377
 378        public:
 379                virtual void StartPixels( int &AStartPixel )
 380                {
 381                        for( int i = 0; i < InputPins.size(); ++i )
 382                        {
 383                                InputPins[ i ].FOwner = this;
 384                                InputPins[ i ].FIndex = AStartPixel + i;
 385                                InputPins[ i ].Value = InitialValue;
 386                                FOwner.SetPixelValue( AStartPixel + i, InitialValue );
 387                        }
 388
 389                        inherited::StartPixels( AStartPixel );
 390                }
 391
 392        public:
 393                using inherited::inherited;
 394
 395        };
 396//---------------------------------------------------------------------------
 397        class MaximLedGroupSection7Segments : public MaximLedGroupBasicBooleanPixels
 398        {
 399                typedef Mitov::MaximLedGroupBasicBooleanPixels inherited;
 400
 401        public:
 402                virtual void StartPixels( int &AStartPixel )
 403                {
 404                        for( int i = 0; i < 7; ++i )
 405                        {
 406                                InputPins[ i ].FOwner = this;
 407                                InputPins[ i ].FIndex = AStartPixel + 6 - i;
 408                                InputPins[ i ].Value = InitialValue;
 409                                FOwner.SetPixelValue( AStartPixel + 6 - i, InitialValue );
 410                        }
 411
 412                        InputPins[ 7 ].FOwner = this;
 413                        InputPins[ 7 ].FIndex = AStartPixel + 7;
 414                        InputPins[ 7 ].Value = InitialValue;
 415                        FOwner.SetPixelValue( AStartPixel + 7, InitialValue );
 416
 417                        inherited::StartPixels( AStartPixel );
 418                }
 419
 420        public:
 421                MaximLedGroupSection7Segments( MaximLedGroupOwner &AOwner ) :
 422                        inherited( AOwner )
 423                {
 424                        InputPins.SetCount( 8 );
 425                        CountPixels = 8;
 426                }
 427        };
 428//---------------------------------------------------------------------------
 429        class MaximLedGroupValueSection7Segments : public MaximLedCommonGroup
 430        {
 431                typedef Mitov::MaximLedCommonGroup inherited;
 432
 433        public:
 434                OpenWire::SinkPin       InputPin;
 435                OpenWire::SinkPin       DecmalPointInputPin;
 436
 437        public:
 438                int             InitialValue = 0;
 439                bool    InitialDecmalPointValue = false;
 440
 441        protected:
 442                int             FValue;
 443                bool    FDecmalPointValue;
 444
 445                int             FStartPixel;
 446
 447        public:
 448                virtual void StartPixels( int &AStartPixel )
 449                {
 450//                      inherited::StartPixels( AStartPixel );
 451                        FStartPixel = AStartPixel;
 452                        AStartPixel += 8;
 453                }
 454
 455        protected:
 456                virtual void UpdateDisplay()
 457                {
 458                        int AValue = (Enabled) ? C_MaximSegments[ FValue & 0xF ] | C_MaximDecimalPoint[ FDecmalPointValue & 1 ] : 0;
 459
 460                        for( int i = 0; i < 8; ++i )
 461                                FOwner.SetPixelValue( FStartPixel + i, ( AValue >> i ) & 1 );
 462                }
 463
 464        protected:
 465                void DoReceive( void *_Data )
 466                {
 467                        int AValue = *(int *)_Data;
 468                        if( FValue == AValue )
 469                                return;
 470
 471                        FValue = AValue;
 472                        UpdateDisplay();
 473                }
 474
 475                void DoReceiveDecmalPoint( void *_Data )
 476                {
 477                        bool AValue = *(bool *)_Data;
 478                        if( FDecmalPointValue == AValue )
 479                                return;
 480
 481                        FDecmalPointValue = AValue;
 482                        UpdateDisplay();
 483                }
 484
 485                virtual void SystemStart() 
 486                {
 487                        FValue = InitialValue;
 488                        FDecmalPointValue = InitialDecmalPointValue;
 489                        inherited::SystemStart();
 490                        UpdateDisplay();
 491                }
 492
 493        public:
 494                MaximLedGroupValueSection7Segments( MaximLedGroupOwner &AOwner ) :
 495                        inherited( AOwner )
 496                {
 497                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedGroupValueSection7Segments::DoReceive );
 498                        DecmalPointInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedGroupValueSection7Segments::DoReceiveDecmalPoint );
 499                }
 500        };
 501//---------------------------------------------------------------------------
 502        class MaximLedGroupBasicMultiDigitDisplay7Segments : public MaximLedCommonGroup
 503        {
 504                typedef Mitov::MaximLedCommonGroup inherited;
 505
 506        public:
 507                uint32_t CountDigits = 8;
 508                bool    ReversedOrder = false;
 509
 510        protected:
 511                int     FStartPixel;
 512
 513        public:
 514                virtual void StartPixels( int &AStartPixel )
 515                {
 516//                      inherited::StartPixels( AStartPixel );
 517                        FStartPixel = AStartPixel;
 518                        AStartPixel += CountDigits * 8;
 519                }
 520
 521        public:
 522                using inherited::inherited;
 523
 524        };
 525//---------------------------------------------------------------------------
 526        template<typename T_DATA> class MaximLedGroupTypedValueDisplay7Segments : public MaximLedGroupBasicMultiDigitDisplay7Segments
 527        {
 528                typedef Mitov::MaximLedGroupBasicMultiDigitDisplay7Segments inherited;
 529
 530        public:
 531                OpenWire::SinkPin       InputPin;
 532
 533        public:
 534                T_DATA  InitialValue;
 535
 536        protected:
 537                T_DATA  FValue;
 538
 539        protected:
 540                virtual byte GetSegmentsValue( int &ADigit ) = 0;
 541
 542                virtual void UpdateDisplay() override
 543                {
 544                        for( int ADigit = 0; ADigit < CountDigits; ++ ADigit )
 545                        {
 546                                byte AValue;
 547                                if( inherited::Enabled )
 548                                        AValue = GetSegmentsValue( ADigit );
 549
 550                                else
 551                                        AValue = 0;
 552
 553                                if( ReversedOrder )
 554                                {
 555                                        for( int i = 0; i < 8; ++i )
 556                                                FOwner.SetPixelValue( FStartPixel + ( CountDigits - ADigit - 1 ) * 8 + i, ( AValue >> i ) & 1 );
 557                                }
 558
 559                                else
 560                                {
 561                                        for( int i = 0; i < 8; ++i )
 562                                                FOwner.SetPixelValue( FStartPixel + ADigit * 8 + i, ( AValue >> i ) & 1 );
 563                                }
 564                        }
 565                }
 566
 567        protected:
 568                void DoReceive( void *_Data )
 569                {
 570                        T_DATA AValue = *(T_DATA *)_Data;
 571                        if( FValue == AValue )
 572                                return;
 573
 574                        FValue = AValue;
 575                        UpdateDisplay();
 576                }
 577
 578                virtual void SystemStart() override
 579                {
 580                        FValue = InitialValue;
 581                        inherited::SystemStart();
 582                        UpdateDisplay();
 583                }
 584
 585        public:
 586                MaximLedGroupTypedValueDisplay7Segments( MaximLedGroupOwner &AOwner ) :
 587                        inherited( AOwner ),
 588                        InitialValue( 0 ) // Needed for specialization
 589                {
 590                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedGroupTypedValueDisplay7Segments::DoReceive );
 591                }
 592        };
 593//---------------------------------------------------------------------------
 594        template<> MaximLedGroupTypedValueDisplay7Segments<String>::MaximLedGroupTypedValueDisplay7Segments( MaximLedGroupOwner &AOwner ) :
 595                        inherited( AOwner )
 596                {
 597                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedGroupTypedValueDisplay7Segments::DoReceive );
 598                }
 599//---------------------------------------------------------------------------
 600        class MaximLedGroupIntegerDisplay7Segments : public MaximLedGroupTypedValueDisplay7Segments<int32_t>
 601        {
 602                typedef Mitov::MaximLedGroupTypedValueDisplay7Segments<int32_t> inherited;
 603
 604        public:
 605                bool    LeadingZeroes = false;
 606
 607        protected:
 608                Mitov::SimpleList<unsigned int> FPowers;
 609                long    FMaxValue; // The biggest possible to display value
 610                long    FMinValue; // The smallest possible to display value
 611
 612        protected:
 613                virtual byte    GetSegmentsValue( int &ADigit )
 614                {
 615                        int AValue;
 616                        if( FValue > FMaxValue )
 617                                AValue = 0b1000000;
 618
 619                        else if( FValue < FMinValue )
 620                                AValue = 0b0001000;
 621
 622                        else
 623                        {
 624                                AValue = ( (int)abs( FValue ) ) / FPowers[ ADigit ];
 625                                if( ( FValue < 0 ) && ( ADigit > 0 ))
 626                                {
 627                                        if( ( !LeadingZeroes ) && ( AValue == 0 ) )
 628                                        {
 629                                                int APreviousValue = ( -FValue ) / FPowers[ ADigit - 1 ];
 630                                                if( APreviousValue > 0 )
 631                                                        AValue = 0b0000001;
 632
 633                                                else
 634                                                        AValue = 0;
 635
 636                                        }
 637
 638                                        else
 639                                        {
 640                                                if( ADigit == CountDigits - 1 )
 641                                                        AValue = 0b1000000;
 642
 643                                                else
 644                                                {
 645                                                        int ADigitValue = AValue % 10;
 646                                                        AValue = C_MaximSegments[ ADigitValue ];
 647                                                }
 648                                        }
 649                                }
 650
 651                                else
 652                                {
 653                                        if( ( !LeadingZeroes ) && ( AValue == 0 ) )
 654                                                AValue = 0;
 655
 656                                        else
 657                                        {
 658                                                int ADigitValue = AValue % 10;
 659                                                AValue = C_MaximSegments[ ADigitValue ];
 660                                        }
 661                                }
 662                        }
 663
 664                        return AValue;
 665                }
 666
 667        public:
 668                virtual void SystemStart() 
 669                {
 670                        FPowers.SetCount( CountDigits );
 671                        for( int i = 0; i < CountDigits; ++i )
 672                                FPowers[ i ] = pow( 10, i ) + 0.5;
 673
 674                        FMaxValue = pow( 10, CountDigits ) + 0.5 - 1;
 675                        FMinValue = -( pow( 10, CountDigits - 1 ) + 0.5 - 1 );
 676
 677                        inherited::SystemStart();
 678                }
 679
 680        public:
 681                using inherited::inherited;
 682
 683        };
 684//---------------------------------------------------------------------------
 685        class MaximLedGroupUnsignedBitPixelsSection : public MaximLedBasicGroup
 686        {
 687                typedef Mitov::MaximLedBasicGroup inherited;
 688
 689        public:
 690                OpenWire::SinkPin       InputPin;
 691
 692        public:
 693                uint32_t        InitialValue = 0;
 694
 695        protected:
 696                uint32_t        FValue = 0;
 697                int                     FStartPixel;
 698
 699        protected:
 700                virtual void StartPixels( int &AStartPixel )
 701                {
 702                        FValue = InitialValue;
 703                        FStartPixel = AStartPixel;
 704                        inherited::StartPixels( AStartPixel );
 705                }
 706
 707                virtual void UpdateDisplay()
 708                {
 709                        for( int i = 0; i < CountPixels; ++i )
 710                                FOwner.SetPixelValue( FStartPixel + i, Enabled && ( FValue >> i ) & 1 );
 711
 712                }
 713
 714                void DoReceive( uint32_t *_Data )
 715                {
 716                        uint32_t AValue = *(uint32_t *)_Data;
 717                        if( FValue == AValue )
 718                                return;
 719
 720                        FValue = AValue;
 721                        UpdateDisplay();
 722                }
 723
 724        public:
 725                MaximLedGroupUnsignedBitPixelsSection( MaximLedGroupOwner &AOwner ) :
 726                        inherited( AOwner )
 727                {
 728                        CountPixels = 32;
 729
 730                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedGroupUnsignedBitPixelsSection::DoReceive );
 731                }
 732        };
 733//---------------------------------------------------------------------------
 734        class MaximLedGroupAnalogDisplay7Segments : public MaximLedGroupTypedValueDisplay7Segments<float>
 735        {
 736                typedef Mitov::MaximLedGroupTypedValueDisplay7Segments<float> inherited;
 737
 738        public:
 739                int             Precision = 2;
 740
 741        protected:
 742                char    *FBuffer;
 743                char    *FStartChar;
 744                byte    FTextLength;
 745                byte    FFirstPos;
 746
 747                char    FDecimalPointPos;
 748
 749        public:
 750                virtual byte    GetSegmentsValue( int &ADigit )
 751                {
 752                        int AValue;
 753                        int ANumDigits = CountDigits;
 754                        if( ! FStartChar )
 755                        {
 756                                FStartChar = dtostrf( FValue, 1, Precision, FBuffer );
 757//                              Serial.println( FStartChar );
 758                                String AText( FStartChar );
 759                                FTextLength = AText.length(); // strlen( FStartChar ); 
 760//                              FTextLength = strlen( FStartChar ); 
 761//                              Serial.println( FTextLength );
 762                                FDecimalPointPos = AText.indexOf( '.' );
 763                                if( Precision == 0 )
 764                                {
 765                                        if( FTextLength <= ANumDigits )
 766                                                FFirstPos = FTextLength - 1;
 767
 768                                        else
 769                                                FFirstPos = ANumDigits - 1;
 770
 771                                
 772//                                      Serial.println( FStartChar );
 773//                                      Serial.println( FTextLength );
 774//                                      Serial.println( FFirstPos );
 775//                                      Serial.println( FDecimalPointPos );
 776                                }
 777
 778                                else
 779                                {
 780                                        if( FTextLength <= ANumDigits + 1 )
 781                                                FFirstPos = FTextLength - 1;
 782
 783                                        else
 784                                                FFirstPos = ANumDigits + 1 - 1;
 785                                }                               
 786
 787//                              Serial.println( FFirstPos );
 788                        }
 789
 790                        int ACorrectedTextLength = FTextLength;
 791                        if( Precision > 0 )
 792                                --ACorrectedTextLength;
 793
 794                        if( ( ACorrectedTextLength - Precision ) > ANumDigits )
 795                        {
 796                                if( FValue > 0 )
 797                                        AValue = 0b1000000; // Overflow +
 798
 799                                else
 800                                        AValue = 0b0001000; // Overflow -
 801                        }
 802
 803                        else
 804                        {
 805                                int ATextPos = FFirstPos - ADigit;
 806                                if( ATextPos < 0 )
 807                                        AValue = 0;
 808
 809                                else
 810                                {
 811                                        if( ATextPos < 0 )
 812                                                return( 0 );
 813
 814                                        bool ADecimalPoint = ( FStartChar[ ATextPos ] == '.' );
 815                                        if( ATextPos <= FDecimalPointPos )
 816                                                --ATextPos;
 817
 818//                                      if( ADecimalPoint )
 819//                                              --ATextPos;
 820
 821                                        if( ATextPos < 0 )
 822                                                return( 0 );
 823
 824/*
 825                                        if( FDigit == 0 )
 826                                        {
 827                                                Serial.println( FStartChar );
 828                                                Serial.println( ATextPos );
 829                                        }
 830*/
 831                                        if( FStartChar[ ATextPos ] == '-' )
 832                                                AValue = 0b0000001;
 833
 834                                        else
 835                                        {
 836                                                AValue = FStartChar[ ATextPos ] - '0';
 837                                                AValue = C_MaximSegments[ AValue ];
 838                                        }
 839
 840                                        if( ADecimalPoint )
 841                                                AValue |= 0x80;
 842
 843                                }
 844                        }
 845
 846                        return AValue;
 847                }
 848
 849                virtual void UpdateDisplay()
 850                {
 851                        FStartChar = NULL;
 852                        inherited::UpdateDisplay();
 853                }
 854
 855        protected:
 856                virtual void SystemStart() 
 857                {
 858                        FBuffer = new char[ 15 + Precision ];
 859                        inherited::SystemStart();
 860                }
 861
 862        public:
 863                using inherited::inherited;
 864
 865        };
 866//---------------------------------------------------------------------------
 867        class MaximLedBasicValueGroup : public MaximLedBasicInitialValueGroup
 868        {
 869                typedef MaximLedBasicInitialValueGroup inherited;
 870
 871        public:
 872                OpenWire::SinkPin       InputPin;
 873
 874        protected:
 875                bool    FValue;
 876
 877        protected:
 878                int FStartPixel;
 879
 880        public:
 881                virtual void StartPixels( int &AStartPixel )
 882                {
 883                        FStartPixel = AStartPixel;
 884                        inherited::StartPixels( AStartPixel );
 885                }
 886
 887        protected:
 888                void DoReceive( void *_Data )
 889                {
 890                        bool AValue = *(bool *)_Data;
 891                        if( FValue == AValue )
 892                                return;
 893
 894                        FValue = AValue;
 895                        UpdateDisplay();
 896                }
 897
 898                virtual void SystemStart() 
 899                {
 900                        FValue = InitialValue;
 901                        inherited::SystemStart();
 902                        UpdateDisplay();
 903                }
 904
 905        public:
 906                MaximLedBasicValueGroup( MaximLedGroupOwner &AOwner ) :
 907                        inherited( AOwner )
 908                {
 909                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedBasicValueGroup::DoReceive );
 910                }
 911        };
 912//---------------------------------------------------------------------------
 913        class MaximLedSingleValueGroup : public MaximLedBasicValueGroup
 914        {
 915                typedef MaximLedBasicValueGroup inherited;
 916
 917        protected:
 918                virtual void UpdateDisplay() override
 919                {
 920                        for( int i = 0; i < CountPixels; ++i )
 921                        {
 922                                if( Enabled )
 923                                        FOwner.SetPixelValue( FStartPixel + i, FValue );
 924
 925                                else
 926                                        FOwner.SetPixelValue( FStartPixel + i, false );
 927                        }
 928                }
 929
 930        public:
 931                using inherited::inherited;
 932
 933        };
 934//---------------------------------------------------------------------------
 935        class MaximLedIndexedPixelGroup : public MaximLedBasicValueGroup
 936        {
 937                typedef MaximLedBasicValueGroup inherited;
 938
 939        public:
 940                OpenWire::SinkPin       IndexInputPin;
 941
 942        public:
 943                uint32_t InitialIndex = 0;
 944
 945        protected:
 946                unsigned long FIndex;
 947
 948        protected:
 949                void DoReceiveIndex( void *_Data )
 950                {
 951                        unsigned long AIndex = *(unsigned long *)_Data;
 952                        if( AIndex > CountPixels )
 953                                AIndex = CountPixels;
 954
 955                        if( FIndex == AIndex )
 956                                return;
 957
 958                        FIndex = AIndex;
 959                        UpdateDisplay();
 960                }
 961
 962                virtual void UpdateDisplay() override
 963                {
 964                        if( Enabled )
 965                                FOwner.SetPixelValue( FStartPixel + FIndex, FValue );
 966
 967                        else
 968                                FOwner.SetPixelValue( FStartPixel + FIndex, false );
 969                }
 970
 971        public:
 972                MaximLedIndexedPixelGroup( MaximLedGroupOwner &AOwner ) :
 973                        inherited( AOwner )
 974                {
 975                        IndexInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedIndexedPixelGroup::DoReceiveIndex );
 976                }
 977        };
 978//---------------------------------------------------------------------------
 979        class MaximLedIndexed2DPixelGroup : public MaximLedBasicValueGroup
 980        {
 981                typedef MaximLedBasicValueGroup inherited;
 982
 983        public:
 984                OpenWire::SinkPin IndexInputPins[ 2 ];
 985
 986        public:
 987                unsigned long Width = 8;
 988                unsigned long InitialIndexX = 0;
 989                unsigned long InitialIndexY = 0;
 990
 991        protected:
 992                unsigned long FIndexX;
 993                unsigned long FIndexY;
 994
 995        protected:
 996                void DoReceiveIndexX( void *_Data )
 997                {
 998                        unsigned long AIndex = *(unsigned long *)_Data;
 999                        if( AIndex > Width )
1000                                AIndex = Width;
1001
1002                        if( FIndexX == AIndex )
1003                                return;
1004
1005                        FIndexX = AIndex;
1006                        UpdateDisplay();
1007                }
1008
1009                void DoReceiveIndexY( void *_Data )
1010                {
1011                        unsigned long AIndex = *(unsigned long *)_Data;
1012                        unsigned long AHeight = ( CountPixels + Width - 1 ) / Width;
1013                        if( AIndex > AHeight )
1014                                AIndex = AHeight;
1015
1016                        if( FIndexY == AIndex )
1017                                return;
1018
1019                        FIndexY = AIndex;
1020                        UpdateDisplay();
1021                }
1022
1023                virtual void UpdateDisplay()
1024                {
1025                        unsigned long AIndex = FStartPixel + FIndexY * Width + FIndexX;
1026                        if( Enabled )
1027                                FOwner.SetPixelValue( AIndex, FValue );
1028
1029                        else
1030                                FOwner.SetPixelValue( AIndex, false );
1031                }
1032
1033        public:
1034                MaximLedIndexed2DPixelGroup( MaximLedGroupOwner &AOwner ) :
1035                        inherited( AOwner )
1036                {
1037                        IndexInputPins[ 0 ].SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedIndexed2DPixelGroup::DoReceiveIndexX );
1038                        IndexInputPins[ 1 ].SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedIndexed2DPixelGroup::DoReceiveIndexY );
1039                }
1040        };
1041//---------------------------------------------------------------------------
1042        class MaximLedRunningPixelGroup;
1043//---------------------------------------------------------------------------
1044        class MaximLedPixelsReversedProperty
1045        {
1046        protected:
1047                MaximLedRunningPixelGroup &FOwner;
1048
1049        public:
1050                bool Reversed : 1;
1051                bool AllPixels : 1;
1052
1053        public:
1054                void SetReversed( bool AValue );
1055
1056        public:
1057                MaximLedPixelsReversedProperty( MaximLedRunningPixelGroup &AOwner ) :
1058                        FOwner( AOwner ),
1059                        Reversed( false ),
1060                        AllPixels( false )
1061                {
1062                }
1063        };
1064//---------------------------------------------------------------------------
1065        class MaximLedRunningPixelGroup : public MaximLedBasicValueGroup
1066        {
1067                typedef MaximLedBasicValueGroup inherited;
1068
1069        public:
1070                OpenWire::ConnectSinkPin        StepInputPin;
1071                OpenWire::SourcePin     OutputPin;
1072
1073        public:
1074                MaximLedPixelsReversedProperty  Reversed;
1075
1076        public:
1077                void ReversePixels()
1078                {
1079                        for( int i = 0; i < CountPixels / 2; ++i )
1080                        {
1081                                bool AOldValue1 = FOwner.GetPixelValue( FStartPixel + ( CountPixels - i - 1 ));
1082                                bool AOldValue2 = FOwner.GetPixelValue( FStartPixel + i );
1083
1084                                FOwner.SetPixelValue( FStartPixel + i, AOldValue1 );
1085                                FOwner.SetPixelValue( FStartPixel + ( CountPixels - i - 1 ), AOldValue2 );
1086                        }
1087                }
1088
1089        protected:
1090                void AnimatePixels()
1091                {
1092                        if( Reversed.Reversed )
1093                        {
1094                                bool AOldValue = FOwner.GetPixelValue( FStartPixel );
1095                                OutputPin.Notify( &AOldValue );
1096                                for( int i = 0; i < CountPixels - 1; ++i )
1097                                {
1098                                        AOldValue = FOwner.GetPixelValue( FStartPixel + i + 1 );
1099                                        FOwner.SetPixelValue( FStartPixel + i, AOldValue );
1100                                }
1101
1102                                FOwner.SetPixelValue( FStartPixel + CountPixels - 1, FValue );
1103                        }
1104
1105                        else
1106                        {
1107                                bool AOldValue = FOwner.GetPixelValue( FStartPixel + CountPixels - 1 );
1108                                OutputPin.Notify( &AOldValue );
1109                                for( int i = CountPixels - 1; i--; )
1110                                {
1111                                        AOldValue = FOwner.GetPixelValue( FStartPixel + i );
1112                                        FOwner.SetPixelValue( FStartPixel + i + 1, AOldValue );
1113                                }
1114
1115                                FOwner.SetPixelValue( FStartPixel, FValue );
1116                        }
1117//                      FOwner->FModified = true;
1118                }
1119
1120                void DoReceiveStep( void *_Data )
1121                {
1122                        AnimatePixels();
1123                }
1124
1125        public:
1126                virtual void PixelsClock( unsigned long currentMicros )
1127                {
1128                        if( StepInputPin.IsConnected())
1129                                return;
1130
1131                        AnimatePixels();
1132                }
1133
1134        public:
1135                MaximLedRunningPixelGroup( MaximLedGroupOwner &AOwner ) :
1136                        inherited( AOwner ),
1137                        Reversed( *this )
1138                {
1139                        StepInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MaximLedRunningPixelGroup::DoReceiveStep );
1140                }
1141        };
1142//---------------------------------------------------------------------------
1143        inline void MaximLedPixelsReversedProperty::SetReversed( bool AValue )
1144        {
1145                if( Reversed == AValue )
1146                        return;
1147
1148                Reversed = AValue;
1149                if( AllPixels )
1150                        FOwner.ReversePixels();
1151
1152        }
1153//---------------------------------------------------------------------------
1154        class MaximLedRepeatGroup : public MaximLedBasicInitialValueGroup, public MaximLedGroupOwner
1155        {
1156                typedef MaximLedBasicInitialValueGroup inherited;
1157
1158        protected:
1159                int FSubPixelCount;
1160                int FRepeatCount;
1161                int     FStartPixel;
1162
1163        public:
1164                virtual void SetPixelValue( int AIndex, bool AValue )
1165                {
1166                        for( int i = 0; i < FRepeatCount; ++i )
1167                                FOwner.SetPixelValue( FStartPixel + AIndex + i * FSubPixelCount, AValue );
1168                }
1169
1170                virtual bool GetPixelValue( int AIndex )
1171                {
1172                        return FOwner.GetPixelValue( FStartPixel + AIndex );
1173                }
1174
1175        public:
1176                virtual void StartPixels( int &AStartPixel ) 
1177                {
1178                        FStartPixel = AStartPixel;
1179                        inherited::StartPixels( AStartPixel );
1180
1181                        FSubPixelCount = 0;
1182                        for( int i = 0; i < FPixelGroups.size(); ++i )
1183                                FPixelGroups[ i ]->StartPixels( FSubPixelCount );
1184
1185                        if( FSubPixelCount == 0 )
1186                                FRepeatCount = 0;
1187
1188                        else
1189                                FRepeatCount = ( CountPixels + FSubPixelCount - 1 ) / FSubPixelCount;
1190
1191                }
1192
1193                virtual void PixelsClock( unsigned long currentMicros )
1194                {
1195                        inherited::PixelsClock( currentMicros );
1196
1197                        for( int i = 0; i < FPixelGroups.size(); ++i )
1198                                FPixelGroups[ i ]->PixelsClock( currentMicros );
1199                }
1200
1201        public:
1202                using inherited::inherited;
1203
1204        };
1205//---------------------------------------------------------------------------
1206}
1207
1208#endif