5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
22 #include "FXExpression.h"
23 #include "FXPNGImage.h"
29 #include "targets/simu/simulcd.h"
31 #if defined(SIMU_AUDIO)
42 #define W2 LCD_W*LCD_ZOOM
43 #define H2 LCD_H*LCD_ZOOM
45 class Open9xSim
: public FXMainWindow
53 void updateKeysAndSwitches(bool start
=false);
54 long onKeypress(FXObject
*,FXSelector
,void*);
55 long onTimeout(FXObject
*,FXSelector
,void*);
56 void createBitmap(int index
, uint16_t *data
, int x
, int y
, int w
, int h
);
57 void makeSnapshot(const FXDrawable
* drawable
);
59 void refreshDisplay();
60 void setPixel(int x
, int y
, FXColor color
);
68 FXSlider
*sliders
[NUM_STICKS
];
69 FXKnob
*knobs
[NUM_POTS
+NUM_SLIDERS
];
73 FXDEFMAP(Open9xSim
) Open9xSimMap
[] = {
74 //Message_Type _________ ID____Message_Handler_______
75 FXMAPFUNC(SEL_TIMEOUT
, 2, Open9xSim::onTimeout
),
76 FXMAPFUNC(SEL_KEYPRESS
, 0, Open9xSim::onKeypress
),
79 FXIMPLEMENT(Open9xSim
,FXMainWindow
,Open9xSimMap
,ARRAYNUMBER(Open9xSimMap
))
81 Open9xSim::Open9xSim(FXApp
* a
):
82 FXMainWindow(a
, "OpenTX Simu", NULL
, NULL
, DECOR_ALL
, 20, 90, 0, 0)
85 memset(displayBuf
, 0, DISPLAY_BUFFER_SIZE
);
86 bmp
= new FXPPMImage(getApp(),NULL
,IMAGE_OWNED
|IMAGE_KEEP
|IMAGE_SHMI
|IMAGE_SHMP
, W2
, H2
);
88 #if defined(SIMU_AUDIO)
89 SDL_Init(SDL_INIT_AUDIO
);
92 FXHorizontalFrame
*hf11
=new FXHorizontalFrame(this,LAYOUT_CENTER_X
);
93 FXHorizontalFrame
*hf1
=new FXHorizontalFrame(this,LAYOUT_FILL_X
);
96 for (int i
=0; i
<4; i
++) {
98 #define L LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|LAYOUT_FIX_X|LAYOUT_FIX_Y
100 sliders
[i
]=new FXSlider(hf1
,NULL
,0,L
|SLIDER_HORIZONTAL
,10,110,100,20);
103 sliders
[i
]=new FXSlider(hf1
,NULL
,0,L
|SLIDER_VERTICAL
,110,10,20,100);
106 sliders
[i
]=new FXSlider(hf1
,NULL
,0,L
|SLIDER_VERTICAL
,130,10,20,100);
109 sliders
[i
]=new FXSlider(hf1
,NULL
,0,L
|SLIDER_HORIZONTAL
,150,110,100,20);
113 sliders
[i
]->setRange(-1024, 1024);
114 sliders
[i
]->setTickDelta(7);
115 sliders
[i
]->setValue(0);
118 for(int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++){
119 knobs
[i
]= new FXKnob(hf11
,NULL
,0,KNOB_TICKS
|LAYOUT_LEFT
);
120 knobs
[i
]->setValue(0);
122 #if defined(PCBHORUS)
123 if (i
== 1) { // 6-pos switch
124 knobs
[i
]->setRange(0, 2048);
125 knobs
[i
]->setIncrement(2048 / 5);
126 knobs
[i
]->setTickDelta(2048 / 5);
130 knobs
[i
]->setRange(-1024, 1024);
133 bmf
= new FXImageFrame(this,bmp
);
135 updateKeysAndSwitches(true);
137 getApp()->addTimeout(this, 2, 100);
140 Open9xSim::~Open9xSim()
154 for(int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++){
160 #if defined(SIMU_AUDIO)
165 void Open9xSim::createBitmap(int index
, uint16_t *data
, int x
, int y
, int w
, int h
)
167 FXPNGImage
snapshot(getApp(), NULL
, IMAGE_OWNED
, w
, h
);
169 for (int i
=0; i
<w
; i
++) {
170 for (int j
=0; j
<h
; j
++) {
171 display_t z
= data
[(y
+j
) * LCD_W
+ (x
+i
)];
172 FXColor color
= FXRGB(255*((z
&0xF00)>>8)/0x0f, 255*((z
&0x0F0)>>4)/0x0f, 255*(z
&0x00F)/0x0f);
173 snapshot
.setPixel(i
, j
, color
);
179 sprintf(buf
,"%02d.png", index
);
180 if (stream
.open(buf
, FXStreamSave
)) {
181 snapshot
.savePixels(stream
);
183 TRACE("Bitmap %d (w=%d, h=%d) created", index
, w
, h
);
186 TRACE("Bitmap %d (w=%d, h=%d) error", index
, w
, h
);
190 void Open9xSim::makeSnapshot(const FXDrawable
* drawable
)
192 // Construct and create an FXImage object
193 FXPNGImage
snapshot(getApp(), NULL
, 0, drawable
->getWidth(), drawable
->getHeight());
196 // Create a window device context and lock it onto the image
197 FXDCWindow
dc(&snapshot
);
199 // Draw from the widget to this
200 dc
.drawArea(drawable
, 0, 0, drawable
->getWidth(), drawable
->getHeight(), 0, 0);
205 // Grab pixels from server side back to client side
208 // Save recovered pixels to a file
214 sprintf(buf
,"snapshot_%02d.png", ++g_snapshot_idx
);
215 } while (stream
.open(buf
, FXStreamLoad
));
217 if (stream
.open(buf
, FXStreamSave
)) {
218 snapshot
.savePixels(stream
);
220 printf("Snapshot written: %s\n", buf
);
223 printf("Cannot create snapshot %s\n", buf
);
227 void Open9xSim::doEvents()
229 getApp()->runOneEvent(false);
232 long Open9xSim::onKeypress(FXObject
*,FXSelector
,void*v
)
234 FXEvent
*evt
=(FXEvent
*)v
;
235 // printf("keypress %x\n", evt->code);
236 if (evt
->code
=='s') {
242 void Open9xSim::updateKeysAndSwitches(bool start
)
244 static int keys1
[] = {
245 #if defined(PCBHORUS)
246 KEY_Page_Up
, KEY_PGUP
,
247 KEY_Page_Down
, KEY_PGDN
,
248 KEY_Return
, KEY_ENTER
,
251 KEY_Right
, KEY_RIGHT
,
253 #elif defined(PCBFLAMENCO)
254 KEY_Page_Up
, KEY_MENU
,
255 KEY_Page_Down
, KEY_PAGE
,
256 KEY_Return
, KEY_ENTER
,
257 KEY_BackSpace
, KEY_EXIT
,
258 #elif defined(PCBTARANIS)
259 KEY_Page_Up
, KEY_MENU
,
260 KEY_Page_Down
, KEY_PAGE
,
261 KEY_Return
, KEY_ENTER
,
262 KEY_BackSpace
, KEY_EXIT
,
266 KEY_Return
, KEY_MENU
,
267 KEY_BackSpace
, KEY_EXIT
,
268 KEY_Right
, KEY_RIGHT
,
272 #if defined(ROTARY_ENCODER_NAVIGATION)
278 for (unsigned int i
=0; i
<DIM(keys1
); i
+=2) {
279 simuSetKey(keys1
[i
+1], start
? false : getApp()->getKeyState(keys1
[i
]));
283 // gruvin: Can't use Function keys on the Mac -- too many other app conflicts.
284 // The ordering of these keys, Q/W,E/R,T/Y,U/I matches the on screen
285 // order of trim sliders
286 static FXuint trimKeys
[] = { KEY_E
, KEY_R
, KEY_U
, KEY_I
, KEY_R
, KEY_E
, KEY_Y
, KEY_T
, KEY_Q
, KEY_W
};
288 static FXuint trimKeys
[] = { KEY_F1
, KEY_F2
, KEY_F3
, KEY_F4
, KEY_F5
, KEY_F6
, KEY_F7
, KEY_F8
, KEY_F9
, KEY_F10
, KEY_F11
, KEY_F12
};
291 for (unsigned i
=0; i
<DIM(trimKeys
); i
++) {
292 simuSetTrim(i
, getApp()->getKeyState(trimKeys
[i
]));
295 #define SWITCH_KEY(key, swtch, states) \
296 static bool state##key = 0; \
297 static int8_t state_##swtch = 2; \
298 static int8_t inc_##swtch = 1; \
299 if (getApp()->getKeyState(KEY_##key)) { \
301 state_##swtch = (state_##swtch+inc_##swtch); \
302 if (state_##swtch == 1+states) inc_##swtch = -1; \
303 else if (state_##swtch == 2) inc_##swtch = 1; \
308 state##key = false; \
310 simuSetSwitch(swtch, state_##swtch-states);
312 #if defined(PCBFLAMENCO)
315 // SWITCH_KEY(C, 2, 3);
316 // SWITCH_KEY(D, 3, 3);
319 #elif defined(PCBX9E)
330 SWITCH_KEY(K
, 10, 3);
331 SWITCH_KEY(L
, 11, 3);
332 SWITCH_KEY(M
, 12, 3);
333 SWITCH_KEY(N
, 13, 3);
334 SWITCH_KEY(O
, 14, 3);
335 SWITCH_KEY(P
, 15, 3);
336 SWITCH_KEY(Q
, 16, 3);
337 SWITCH_KEY(R
, 17, 3);
338 #elif defined(PCBTARANIS) || defined(PCBHORUS)
358 long Open9xSim::onTimeout(FXObject
*, FXSelector
, void*)
361 #if defined(COPROCESSOR)
366 #if defined(PCBSKY9X)
371 updateKeysAndSwitches();
373 #if defined(ROTARY_ENCODER_NAVIGATION)
374 static bool rotencAction
= false;
375 if (getApp()->getKeyState(KEY_X
)) {
376 if (!rotencAction
) ROTARY_ENCODER_NAVIGATION_VALUE
+= ROTARY_ENCODER_GRANULARITY
;
379 else if (getApp()->getKeyState(KEY_W
)) {
380 if (!rotencAction
) ROTARY_ENCODER_NAVIGATION_VALUE
-= ROTARY_ENCODER_GRANULARITY
;
384 rotencAction
= false;
399 SWITCH_KEY(K
, 10, 3);
400 SWITCH_KEY(L
, 11, 3);
401 SWITCH_KEY(M
, 12, 3);
402 SWITCH_KEY(N
, 13, 3);
403 SWITCH_KEY(O
, 14, 3);
404 SWITCH_KEY(P
, 15, 3);
405 SWITCH_KEY(Q
, 16, 3);
406 SWITCH_KEY(R
, 17, 3);
407 #elif defined(PCBTARANIS) || defined(PCBHORUS)
433 static int timeToRefresh
;
434 if (++timeToRefresh
>= 5) {
438 getApp()->addTimeout(this, 2, 10);
443 #define BL_COLOR FXRGB(47, 123, 227)
445 #define BL_COLOR FXRGB(150, 200, 152)
448 void Open9xSim::setPixel(int x
, int y
, FXColor color
)
451 for (int i
=0; i
<LCD_ZOOM
; ++i
) {
452 for (int j
=0; j
<LCD_ZOOM
; ++j
) {
453 bmp
->setPixel(LCD_ZOOM
*x
+i
, LCD_ZOOM
*y
+j
, color
);
457 bmp
->setPixel(x
, y
, color
);
461 void Open9xSim::refreshDisplay()
463 if (simuLcdRefresh
) {
464 simuLcdRefresh
= false;
465 FXColor offColor
= isBacklightEnabled() ? BL_COLOR
: FXRGB(200, 200, 200);
467 FXColor onColor
= FXRGB(0, 0, 0);
469 for (int x
=0; x
<LCD_W
; x
++) {
470 for (int y
=0; y
<LCD_H
; y
++) {
471 #if defined(PCBHORUS)
472 display_t z
= simuLcdBuf
[y
* LCD_W
+ x
];
475 setPixel(x
, y
, FXRGB(0,0,0));
477 else if (z
== 0xFFFF) {
478 setPixel(x
, y
, FXRGB(255,255,255));
481 FXColor color
= FXRGB(255*((z
&0xF800)>>11)/0x1f, 255*((z
&0x07E0)>>5)/0x3F, 255*(z
&0x001F)/0x01F);
482 setPixel(x
, y
, color
);
485 #elif defined(PCBFLAMENCO)
486 display_t z
= simuLcdBuf
[y
* LCD_W
+ x
];
488 FXColor color
= FXRGB(255*((z
&0xF00)>>8)/0x0f, 255*((z
&0x0F0)>>4)/0x0f, 255*(z
&0x00F)/0x0f);
489 setPixel(x
, y
, color
);
492 display_t
* p
= &simuLcdBuf
[y
/ 2 * LCD_W
+ x
];
493 uint8_t z
= (y
& 1) ? (*p
>> 4) : (*p
& 0x0F);
496 if (isBacklightEnabled())
497 color
= FXRGB(47-(z
*47)/15, 123-(z
*123)/15, 227-(z
*227)/15);
499 color
= FXRGB(200-(z
*200)/15, 200-(z
*200)/15, 200-(z
*200)/15);
500 setPixel(x
, y
, color
);
503 if (simuLcdBuf
[x
+(y
/8)*LCD_W
] & (1<<(y
%8))) {
504 setPixel(x
, y
, onColor
);
508 setPixel(x
, y
, offColor
);
521 //puts("doFxEvents");
522 th9xSim
->getApp()->runOneEvent(false);
523 th9xSim
->refreshDisplay();
526 int main(int argc
,char **argv
)
528 // Each FOX GUI program needs one, and only one, application object.
529 // The application objects coordinates some common stuff shared between
530 // all the widgets; for example, it dispatches events, keeps track of
531 // all the windows, and so on.
532 // We pass the "name" of the application, and its "vendor", the name
533 // and vendor are used to search the registry database (which stores
534 // persistent information e.g. fonts and colors).
535 FXApp
application("OpenTX Simu", "OpenTX");
537 // Here we initialize the application. We pass the command line arguments
538 // because FOX may sometimes need to filter out some of the arguments.
539 // This opens up the display as well, and reads the registry database
540 // so that persistent settings are now available.
541 application
.init(argc
,argv
);
543 // This creates the main window. We pass in the title to be displayed
544 // above the window, and possibly some icons for when its iconified.
545 // The decorations determine stuff like the borders, close buttons,
546 // drag handles, and so on the Window Manager is supposed to give this
548 //FXMainWindow *main=new FXMainWindow(&application,"Hello",NULL,NULL,DECOR_ALL);
549 th9xSim
= new Open9xSim(&application
);
550 application
.create();
552 // Pretty self-explanatory:- this shows the window, and places it in the
553 // middle of the screen.
555 th9xSim
->show(PLACEMENT_SCREEN
);
557 th9xSim
->show(); // Otherwise the main window gets centred across my two monitors, split down the middle.
560 #if defined(TELEMETRY_FRSKY) && !defined(TELEMETRY_FRSKY_SPORT)
561 telemetryStreaming
= 1;
564 printf("Model size = %d\n", (int)sizeof(g_model
));
569 StartEepromThread(argc
>= 2 ? argv
[1] : "eeprom.bin");
572 StartSimu(false, argc
>= 3 ? argv
[2] : 0, argc
>= 4 ? argv
[3] : 0);
574 return application
.run();
577 uint16_t anaIn(uint8_t chan
)
580 return th9xSim
->sliders
[chan
]->getValue();
581 else if (chan
<NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
)
582 return th9xSim
->knobs
[chan
-NUM_STICKS
]->getValue();
583 #if defined(PCBHORUS)
584 else if (chan
== TX_VOLTAGE
)
585 return 1737; //~10.6V
586 #elif defined(PCBX9E)
587 else if (chan
== TX_VOLTAGE
)
588 return 1420; //~10.6V
589 #elif defined(PCBTARANIS) || defined(PCBFLAMENCO)
590 else if (chan
== TX_VOLTAGE
)
592 #elif defined(PCBSKY9X)
593 else if (chan
== TX_VOLTAGE
)
594 return 5.1*1500/11.3;
595 else if (chan
== TX_CURRENT
)
597 #elif defined(PCBGRUVIN9X)
598 else if (chan
== TX_VOLTAGE
)
601 else if (chan
== TX_VOLTAGE
)
608 uint16_t getAnalogValue(uint8_t index
)
613 void createBitmap(int index
, uint16_t *data
, int x
, int y
, int w
, int h
)
615 th9xSim
->createBitmap(index
, data
, x
, y
, w
, h
);