wii_anal_lcd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #include "wii_anal.h"
  2. #include "gfx/images.h" // Images
  3. //----------------------------------------------------------------------------- ----------------------------------------
  4. // A couple of monospaced hex fonts
  5. //
  6. const image_t* img_6x8[16] = {
  7. &img_6x8_0,
  8. &img_6x8_1,
  9. &img_6x8_2,
  10. &img_6x8_3,
  11. &img_6x8_4,
  12. &img_6x8_5,
  13. &img_6x8_6,
  14. &img_6x8_7,
  15. &img_6x8_8,
  16. &img_6x8_9,
  17. &img_6x8_A,
  18. &img_6x8_B,
  19. &img_6x8_C,
  20. &img_6x8_D,
  21. &img_6x8_E,
  22. &img_6x8_F,
  23. };
  24. const image_t* img_5x7[16] = {
  25. &img_5x7_0,
  26. &img_5x7_1,
  27. &img_5x7_2,
  28. &img_5x7_3,
  29. &img_5x7_4,
  30. &img_5x7_5,
  31. &img_5x7_6,
  32. &img_5x7_7,
  33. &img_5x7_8,
  34. &img_5x7_9,
  35. &img_5x7_A,
  36. &img_5x7_B,
  37. &img_5x7_C,
  38. &img_5x7_D,
  39. &img_5x7_E,
  40. &img_5x7_F,
  41. };
  42. //+============================================================================ ========================================
  43. // void backlightOn (void)
  44. // {
  45. // // Acquire a handle for the system notification queue
  46. // // Do this ONCE ... at plugin startup
  47. // NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
  48. //
  49. // // Pat the backlight watchdog
  50. // // Send the (predefined) message sequence {backlight_on, end}
  51. // // --> applications/notification/*.c
  52. // notification_message(notifications, &sequence_display_backlight_on);
  53. //
  54. // // Release the handle for the system notification queue
  55. // // Do this ONCE ... at plugin quit
  56. // furi_record_close(RECORD_NOTIFICATION);
  57. // }
  58. void patBacklight(state_t* state) {
  59. notification_message(state->notify, &sequence_display_backlight_on);
  60. }
  61. //============================================================================= ========================================
  62. // Show a hex number in an inverted box (for ananlogue readings)
  63. //
  64. void showHex(
  65. Canvas* const canvas,
  66. uint8_t x,
  67. uint8_t y,
  68. const uint32_t val,
  69. const uint8_t cnt,
  70. const int b) {
  71. canvas_set_color(canvas, ColorBlack);
  72. canvas_draw_box(canvas, x++, y++, 1 + (cnt * (6 + 1)), 10);
  73. // thicken border
  74. if(b == 2) canvas_draw_frame(canvas, x - 2, y - 2, 1 + (cnt * (6 + 1)) + 2, 10 + 2);
  75. for(int i = (cnt - 1) * 4; i >= 0; i -= 4, x += 6 + 1)
  76. show(canvas, x, y, img_6x8[(val >> i) & 0xF], SHOW_SET_WHT);
  77. }
  78. //============================================================================= ========================================
  79. // Show the up/down "peak hold" controls in the bottom right
  80. //
  81. void showPeakHold(state_t* const state, Canvas* const canvas, const int hold) {
  82. switch(hold) {
  83. case 0:
  84. show(canvas, 119, 51, &img_key_U, SHOW_CLR_BLK);
  85. show(canvas, 119, 56, &img_key_D, SHOW_CLR_BLK);
  86. break;
  87. case +1:
  88. canvas_set_color(canvas, ColorBlack);
  89. canvas_draw_box(canvas, 120, 52, 7, 6);
  90. show(canvas, 119, 51, &img_key_U, SHOW_CLR_WHT);
  91. show(canvas, 119, 56, &img_key_D, SHOW_CLR_BLK);
  92. break;
  93. case -1:
  94. show(canvas, 119, 51, &img_key_U, SHOW_CLR_BLK);
  95. canvas_draw_box(canvas, 120, 57, 7, 6);
  96. show(canvas, 119, 56, &img_key_D, SHOW_CLR_WHT);
  97. break;
  98. default:
  99. break;
  100. }
  101. canvas_set_color(canvas, ColorBlack);
  102. canvas_draw_frame(canvas, 119, 51, 9, 13);
  103. // calibration indicator
  104. show(
  105. canvas,
  106. 108,
  107. 55,
  108. ((state->calib & CAL_RANGE) && (++state->flash & 8)) ? &img_key_OKi : &img_key_OK,
  109. SHOW_SET_BLK);
  110. }
  111. //============================================================================= ========================================
  112. // This code performs a FULL calibration on the device EVERY time it draws a joystick
  113. //...This is NOT a good way forward for anything other than a test tool.
  114. //
  115. // Realistically you would do all the maths when the controller is connected
  116. // or, if you prefer (and it IS a good thing), have a "calibrate controller" menu option
  117. // ...and then just use a lookup table, or trivial formual
  118. //
  119. // THIS algorithm chops the joystick in to one of 9 zones
  120. // Eg. {FullLeft, Left3, Left2, Left1, Middle, Right1, Right2, Right3, FullRight}
  121. // FullLeft and FullRight have a deadzone of N [qv. xDead] ..a total of N+1 positions
  122. // Middle has a deadzone of N EACH WAY ...a total of 2N+1 positions
  123. //
  124. // If the remaining range does not divide evenly in to three zones,
  125. // the first remainder is added to zone3,
  126. // and the second remainder (if there is one) is added to zone2
  127. // ...giving finer control near the centre of the joystick
  128. //
  129. // The value of the deadzone is based on the number of bits in the
  130. // joystcik {x,y} values - the larger the range, the larger the deadzone.
  131. //
  132. // 03 15 29
  133. // |<<| Calibration points |==| |>>|
  134. // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
  135. // |---| |________________________| |------| |______________________________| |---|
  136. // |r=2| | range = 9 | | r=3 | | range = 11 | |r=2|
  137. // Zones: |-4 | |-3 |-2 |-1 | |0 | |+1 |+2 |+3 | |+4 |
  138. //
  139. // This is not "the right way to do it" ...this is "one way to do it"
  140. // Consider you application, and what the user is trying to achieve
  141. // Aim a gun - probably need to be more accurate
  142. // Turn and object - this is probably good enough
  143. // Start slowly & pick up speed - how about a log or sine curve?
  144. //
  145. void showJoy(
  146. Canvas* const canvas,
  147. const uint8_t x,
  148. const uint8_t y, // x,y is the CENTRE of the Joystick
  149. const uint8_t xMin,
  150. const uint8_t xMid,
  151. const uint8_t xMax,
  152. const uint8_t yMin,
  153. const uint8_t yMid,
  154. const uint8_t yMax,
  155. const uint8_t xPos,
  156. const uint8_t yPos,
  157. const uint8_t bits) {
  158. int xOff = 0; // final offset of joystick hat image
  159. int yOff = 0;
  160. int xDead = (bits < 7) ? (1 << 0) : (1 << 3); // dead zone (centre & limits)
  161. int yDead = xDead;
  162. // This code is NOT optimised ...and it's still barely readable!
  163. if((xPos >= (xMid - xDead)) && (xPos <= (xMid + xDead)))
  164. xOff = 0; // centre [most likely]
  165. else if(xPos <= (xMin + xDead))
  166. xOff = -4; // full left
  167. else if(xPos >= (xMax - xDead))
  168. xOff = +4; // full right
  169. else if(xPos < (xMid - xDead)) { // part left
  170. // very much hard-coded for 3 interim positions
  171. int lo = (xMin + xDead) + 1; // lowest position
  172. int hi = (xMid - xDead) - 1; // highest position
  173. // this is the only duplicated bit of code
  174. int range = (hi - lo) + 1; // range covered
  175. int div = range / 3; // each division (base amount, eg. 17/3==5)
  176. int rem = range - (div * 3); // remainder (ie. range%3)
  177. // int hi1 = hi; // lowest value for zone #-1
  178. // int lo1 = hi1 -div +1; // highest value for zone #-1
  179. // int hi2 = lo1 -1; // lowest value for zone #-2
  180. // int lo2 = hi2 -div +1 -(rem==2); // highest value for zone #-2 expand out remainder
  181. // int hi3 = lo2 -1; // lowest value for zone #-3
  182. // int lo3 = hi3 -div +1 -(rem>=1); // highest value for zone #-3 expand out remainder
  183. int lo1 = hi - div + 1; // (in brevity)
  184. int hi3 = hi - div - div - (rem == 2); // ...
  185. if(xPos <= hi3)
  186. xOff = -3; // zone #-3
  187. else if(xPos >= lo1)
  188. xOff = -1; // zone #-1
  189. else
  190. xOff = -2; // zone #-2
  191. } else /*if (xPos > (xMid +xDead))*/ { // part right
  192. // very much hard-coded for 3 interim positions
  193. int lo = (xMid + xDead) + 1; // lowest position
  194. int hi = (xMax - xDead) - 1; // highest position
  195. int range = (hi - lo) + 1; // range covered
  196. int div = range / 3; // each division (base amount, eg. 17/3==5)
  197. int rem = range - (div * 3); // remainder (ie. range%3)
  198. // int lo1 = lo; // lowest value for zone #+1
  199. // int hi1 = lo +div -1; // highest value for zone #+1
  200. // int lo2 = hi1 +1; // lowest value for zone #+2
  201. // int hi2 = lo2 +div -1 +(rem==2); // highest value for zone #+2 expand out remainder
  202. // int lo3 = hi2 +1; // lowest value for zone #+3
  203. // int hi3 = lo3 +div -1 +(rem>=1); // highest value for zone #+3 expand out remainder
  204. int hi1 = lo + div - 1; // (in brevity)
  205. int lo3 = lo + div + div + (rem == 2); // ...
  206. if(xPos <= hi1)
  207. xOff = 1; // zone #1
  208. else if(xPos >= lo3)
  209. xOff = 3; // zone #3
  210. else
  211. xOff = 2; // zone #2
  212. }
  213. // All this to print a 3x3 square (in the right place) - LOL!
  214. if((yPos >= (yMid - yDead)) && (yPos <= (yMid + yDead)))
  215. yOff = 0; // centre [most likely]
  216. else if(yPos <= (yMin + yDead))
  217. yOff = +4; // full down
  218. else if(yPos >= (yMax - yDead))
  219. yOff = -4; // full up
  220. else if(yPos < (yMid - yDead)) { // part down
  221. int lo = (yMin + yDead) + 1; // lowest position
  222. int hi = (yMid - yDead) - 1; // highest position
  223. int range = (hi - lo) + 1; // range covered
  224. int div = range / 3; // each division (base amount, eg. 17/3==5)
  225. int rem = range - (div * 3); // remainder (ie. range%3)
  226. int lo1 = hi - div + 1; // (in brevity)
  227. int hi3 = hi - div - div - (rem == 2); // ...
  228. if(yPos <= hi3)
  229. yOff = +3; // zone #3
  230. else if(yPos >= lo1)
  231. yOff = +1; // zone #1
  232. else
  233. yOff = +2; // zone #2
  234. } else /*if (yPos > (yMid +yDead))*/ { // part up
  235. int lo = (yMid + yDead) + 1; // lowest position
  236. int hi = (yMax - yDead) - 1; // highest position
  237. int range = (hi - lo) + 1; // range covered
  238. int div = range / 3; // each division (base amount, eg. 17/3==5)
  239. int rem = range - (div * 3); // remainder (ie. range%3)
  240. int hi1 = lo + div - 1; // (in brevity)
  241. int lo3 = lo + div + div + (rem == 2); // ...
  242. if(yPos <= hi1)
  243. yOff = -1; // zone #-1
  244. else if(yPos >= lo3)
  245. yOff = -3; // zone #-3
  246. else
  247. yOff = -2; // zone #-2
  248. }
  249. show(canvas, x - (img_cc_Joy.w / 2), y - (img_cc_Joy.h / 2), &img_cc_Joy, SHOW_SET_BLK);
  250. // All ^that^ for v-this-v - LOL!!
  251. canvas_draw_box(canvas, (x - 1) + xOff, (y - 1) + yOff, 3, 3);
  252. }