Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of DMBasicGUI by
SlideShow/Renderer.cpp@38:1b7c79a10e14, 2016-03-14 (annotated)
- Committer:
- redbird
- Date:
- Mon Mar 14 20:14:06 2016 -0600
- Revision:
- 38:1b7c79a10e14
- Parent:
- 15:a68bb30ab95e
revert programming
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 13:bff2288c2c61 | 1 | /* |
embeddedartists | 13:bff2288c2c61 | 2 | * Copyright 2014 Embedded Artists AB |
embeddedartists | 13:bff2288c2c61 | 3 | * |
embeddedartists | 13:bff2288c2c61 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
embeddedartists | 13:bff2288c2c61 | 5 | * you may not use this file except in compliance with the License. |
embeddedartists | 13:bff2288c2c61 | 6 | * You may obtain a copy of the License at |
embeddedartists | 13:bff2288c2c61 | 7 | * |
embeddedartists | 13:bff2288c2c61 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
embeddedartists | 13:bff2288c2c61 | 9 | * |
embeddedartists | 13:bff2288c2c61 | 10 | * Unless required by applicable law or agreed to in writing, software |
embeddedartists | 13:bff2288c2c61 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
embeddedartists | 13:bff2288c2c61 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
embeddedartists | 13:bff2288c2c61 | 13 | * See the License for the specific language governing permissions and |
embeddedartists | 13:bff2288c2c61 | 14 | * limitations under the License. |
embeddedartists | 13:bff2288c2c61 | 15 | */ |
embeddedartists | 13:bff2288c2c61 | 16 | |
embeddedartists | 5:f4de114c31c3 | 17 | #include "mbed.h" |
embeddedartists | 5:f4de114c31c3 | 18 | #include "Renderer.h" |
embeddedartists | 5:f4de114c31c3 | 19 | #include "DMBoard.h" |
embeddedartists | 5:f4de114c31c3 | 20 | |
embeddedartists | 13:bff2288c2c61 | 21 | /****************************************************************************** |
embeddedartists | 13:bff2288c2c61 | 22 | * Defines and typedefs |
embeddedartists | 13:bff2288c2c61 | 23 | *****************************************************************************/ |
embeddedartists | 13:bff2288c2c61 | 24 | |
embeddedartists | 5:f4de114c31c3 | 25 | #if !defined(MIN) |
embeddedartists | 5:f4de114c31c3 | 26 | #define MIN(__a, __b) (((__a)<(__b))?(__a):(__b)) |
embeddedartists | 5:f4de114c31c3 | 27 | #endif |
embeddedartists | 5:f4de114c31c3 | 28 | |
embeddedartists | 13:bff2288c2c61 | 29 | /****************************************************************************** |
embeddedartists | 13:bff2288c2c61 | 30 | * Public functions |
embeddedartists | 13:bff2288c2c61 | 31 | *****************************************************************************/ |
embeddedartists | 13:bff2288c2c61 | 32 | |
embeddedartists | 13:bff2288c2c61 | 33 | Renderer::Renderer() |
embeddedartists | 5:f4de114c31c3 | 34 | { |
embeddedartists | 5:f4de114c31c3 | 35 | memset(layers, 0, sizeof(layerinfo_t)*MaxNumLayers); |
embeddedartists | 5:f4de114c31c3 | 36 | for (int i = 0; i < MaxNumLayers; i++) { |
embeddedartists | 5:f4de114c31c3 | 37 | layers[i].used = false; |
embeddedartists | 5:f4de114c31c3 | 38 | order[i] = NULL; |
embeddedartists | 5:f4de114c31c3 | 39 | } |
embeddedartists | 5:f4de114c31c3 | 40 | |
embeddedartists | 5:f4de114c31c3 | 41 | numRegisteredLayers = 0; |
embeddedartists | 5:f4de114c31c3 | 42 | activeBackBuffer = 0; |
embeddedartists | 5:f4de114c31c3 | 43 | display = DMBoard::instance().display(); |
embeddedartists | 5:f4de114c31c3 | 44 | |
embeddedartists | 5:f4de114c31c3 | 45 | this->screenWidth = display->width(); |
embeddedartists | 5:f4de114c31c3 | 46 | this->screenHeight = display->height(); |
embeddedartists | 5:f4de114c31c3 | 47 | this->screenPixels = this->screenWidth * this->screenHeight; |
embeddedartists | 5:f4de114c31c3 | 48 | |
embeddedartists | 5:f4de114c31c3 | 49 | // Assume screen->bpp == Bpp_16 |
embeddedartists | 5:f4de114c31c3 | 50 | this->screenBytes = display->bytesPerPixel() * this->screenPixels; |
embeddedartists | 5:f4de114c31c3 | 51 | |
embeddedartists | 13:bff2288c2c61 | 52 | ImageBackBuffer[0] = (image_t)display->allocateFramebuffer(); |
embeddedartists | 13:bff2288c2c61 | 53 | ImageBackBuffer[1] = (image_t)display->allocateFramebuffer(); |
embeddedartists | 5:f4de114c31c3 | 54 | if ((ImageBackBuffer[0] == NULL) || (ImageBackBuffer[1] == NULL)) { |
embeddedartists | 5:f4de114c31c3 | 55 | printf("Failed to allocate buffer(s) for Renderer. Halting...\n"); |
embeddedartists | 5:f4de114c31c3 | 56 | while(1) { |
embeddedartists | 5:f4de114c31c3 | 57 | ; |
embeddedartists | 5:f4de114c31c3 | 58 | } |
embeddedartists | 5:f4de114c31c3 | 59 | } |
embeddedartists | 5:f4de114c31c3 | 60 | memset(ImageBackBuffer[0], 0xff, screenBytes); |
embeddedartists | 5:f4de114c31c3 | 61 | memset(ImageBackBuffer[1], 0xff, screenBytes); |
embeddedartists | 5:f4de114c31c3 | 62 | } |
embeddedartists | 5:f4de114c31c3 | 63 | |
embeddedartists | 5:f4de114c31c3 | 64 | Renderer::~Renderer() |
embeddedartists | 5:f4de114c31c3 | 65 | { |
embeddedartists | 5:f4de114c31c3 | 66 | free(ImageBackBuffer[0]); |
embeddedartists | 5:f4de114c31c3 | 67 | free(ImageBackBuffer[1]); |
embeddedartists | 5:f4de114c31c3 | 68 | for (int i = 0; i < MaxNumLayers; i++) { |
embeddedartists | 5:f4de114c31c3 | 69 | if (layers[i].used) { |
embeddedartists | 5:f4de114c31c3 | 70 | free(layers[i].tmp); |
embeddedartists | 5:f4de114c31c3 | 71 | delete(layers[i].lock); |
embeddedartists | 5:f4de114c31c3 | 72 | } |
embeddedartists | 5:f4de114c31c3 | 73 | } |
embeddedartists | 5:f4de114c31c3 | 74 | } |
embeddedartists | 5:f4de114c31c3 | 75 | |
embeddedartists | 5:f4de114c31c3 | 76 | uint32_t Renderer::registerUser(int layer, int xoff, int yoff, int width, int height) |
embeddedartists | 5:f4de114c31c3 | 77 | { |
embeddedartists | 5:f4de114c31c3 | 78 | setupMutex.lock(); |
embeddedartists | 5:f4de114c31c3 | 79 | if (numRegisteredLayers < MaxNumLayers) { |
embeddedartists | 5:f4de114c31c3 | 80 | for (int i = 0; i < MaxNumLayers; i++) { |
embeddedartists | 5:f4de114c31c3 | 81 | if (!layers[i].used) { |
embeddedartists | 5:f4de114c31c3 | 82 | // found a spot |
embeddedartists | 5:f4de114c31c3 | 83 | layers[i].used = true; |
embeddedartists | 5:f4de114c31c3 | 84 | layers[i].x0 = xoff; |
embeddedartists | 5:f4de114c31c3 | 85 | layers[i].y0 = yoff; |
embeddedartists | 5:f4de114c31c3 | 86 | layers[i].x1 = MIN(xoff+width, screenWidth); |
embeddedartists | 5:f4de114c31c3 | 87 | layers[i].y1 = MIN(yoff+height, screenHeight); |
embeddedartists | 5:f4de114c31c3 | 88 | layers[i].width = width; |
embeddedartists | 5:f4de114c31c3 | 89 | layers[i].clippedHeight = layers[i].y1 - layers[i].y0; |
embeddedartists | 5:f4de114c31c3 | 90 | layers[i].zorder = layer; |
embeddedartists | 5:f4de114c31c3 | 91 | layers[i].signalId = 1;//(1<<i); |
embeddedartists | 5:f4de114c31c3 | 92 | layers[i].lock = new Mutex(); |
embeddedartists | 5:f4de114c31c3 | 93 | layers[i].newData = NULL; |
embeddedartists | 5:f4de114c31c3 | 94 | layers[i].activeData = NULL; |
embeddedartists | 5:f4de114c31c3 | 95 | layers[i].fullscreen = false; |
embeddedartists | 5:f4de114c31c3 | 96 | if ((xoff == 0) && (yoff == 0) && (width == screenWidth) && (height == screenHeight)) { |
embeddedartists | 5:f4de114c31c3 | 97 | layers[i].fullscreen = true; |
embeddedartists | 5:f4de114c31c3 | 98 | } |
embeddedartists | 5:f4de114c31c3 | 99 | |
embeddedartists | 5:f4de114c31c3 | 100 | layers[i].tmp = (uint16_t*)malloc(width*layers[i].clippedHeight*2); |
embeddedartists | 5:f4de114c31c3 | 101 | if (layers[i].tmp != NULL) { |
embeddedartists | 5:f4de114c31c3 | 102 | memset(layers[i].tmp, 0, width*layers[i].clippedHeight*2); |
embeddedartists | 5:f4de114c31c3 | 103 | } |
embeddedartists | 5:f4de114c31c3 | 104 | |
embeddedartists | 5:f4de114c31c3 | 105 | |
embeddedartists | 5:f4de114c31c3 | 106 | // sort the order |
embeddedartists | 5:f4de114c31c3 | 107 | for (int j = 0; j < MaxNumLayers; j++) { |
embeddedartists | 5:f4de114c31c3 | 108 | if (order[j] == NULL) { |
embeddedartists | 5:f4de114c31c3 | 109 | // no more layers so add the new one to the top |
embeddedartists | 5:f4de114c31c3 | 110 | order[j] = &(layers[i]); |
embeddedartists | 5:f4de114c31c3 | 111 | break; |
embeddedartists | 5:f4de114c31c3 | 112 | } |
embeddedartists | 5:f4de114c31c3 | 113 | if (order[j]->zorder > layer) { |
embeddedartists | 5:f4de114c31c3 | 114 | // should insert the new layer here |
embeddedartists | 5:f4de114c31c3 | 115 | for (int k = numRegisteredLayers; k > j; k--) { |
embeddedartists | 5:f4de114c31c3 | 116 | order[k] = order[k-1]; |
embeddedartists | 5:f4de114c31c3 | 117 | } |
embeddedartists | 5:f4de114c31c3 | 118 | order[j] = &(layers[i]); |
embeddedartists | 5:f4de114c31c3 | 119 | break; |
embeddedartists | 5:f4de114c31c3 | 120 | } |
embeddedartists | 5:f4de114c31c3 | 121 | } |
embeddedartists | 5:f4de114c31c3 | 122 | |
embeddedartists | 5:f4de114c31c3 | 123 | // Cause a repaint of all layers. It does not have to be immediate |
embeddedartists | 5:f4de114c31c3 | 124 | // as for unregisterUser() - it is enough that it is done next time. |
embeddedartists | 5:f4de114c31c3 | 125 | order[0]->activeData = NULL; |
embeddedartists | 5:f4de114c31c3 | 126 | |
embeddedartists | 5:f4de114c31c3 | 127 | numRegisteredLayers++; |
embeddedartists | 5:f4de114c31c3 | 128 | |
embeddedartists | 5:f4de114c31c3 | 129 | setupMutex.unlock(); |
embeddedartists | 5:f4de114c31c3 | 130 | return (uint32_t)(&(layers[i])); |
embeddedartists | 5:f4de114c31c3 | 131 | } |
embeddedartists | 5:f4de114c31c3 | 132 | } |
embeddedartists | 5:f4de114c31c3 | 133 | } |
embeddedartists | 5:f4de114c31c3 | 134 | setupMutex.unlock(); |
embeddedartists | 5:f4de114c31c3 | 135 | return 0; |
embeddedartists | 5:f4de114c31c3 | 136 | } |
embeddedartists | 5:f4de114c31c3 | 137 | |
embeddedartists | 5:f4de114c31c3 | 138 | uint32_t Renderer::registerFullscreenUser(int layer) |
embeddedartists | 5:f4de114c31c3 | 139 | { |
embeddedartists | 5:f4de114c31c3 | 140 | return registerUser(layer, 0, 0, screenWidth, screenHeight); |
embeddedartists | 5:f4de114c31c3 | 141 | } |
embeddedartists | 5:f4de114c31c3 | 142 | |
embeddedartists | 5:f4de114c31c3 | 143 | void Renderer::unregisterUser(uint32_t handle) |
embeddedartists | 5:f4de114c31c3 | 144 | { |
embeddedartists | 5:f4de114c31c3 | 145 | setupMutex.lock(); |
embeddedartists | 5:f4de114c31c3 | 146 | if (handle != 0) { |
embeddedartists | 5:f4de114c31c3 | 147 | layerinfo_t* layer = (layerinfo_t*)handle; |
embeddedartists | 5:f4de114c31c3 | 148 | for (int i = 0; i < MaxNumLayers; i++) { |
embeddedartists | 5:f4de114c31c3 | 149 | if (order[i] == layer) { |
embeddedartists | 5:f4de114c31c3 | 150 | layer->used = false; |
embeddedartists | 5:f4de114c31c3 | 151 | free(layer->tmp); |
embeddedartists | 5:f4de114c31c3 | 152 | delete layer->lock; |
embeddedartists | 5:f4de114c31c3 | 153 | |
embeddedartists | 5:f4de114c31c3 | 154 | // move all layers "down" one step |
embeddedartists | 5:f4de114c31c3 | 155 | for (int j = i+1; j<numRegisteredLayers; j++) { |
embeddedartists | 5:f4de114c31c3 | 156 | order[j-1] = order[j]; |
embeddedartists | 5:f4de114c31c3 | 157 | } |
embeddedartists | 5:f4de114c31c3 | 158 | order[numRegisteredLayers-1] = NULL; |
embeddedartists | 5:f4de114c31c3 | 159 | numRegisteredLayers--; |
embeddedartists | 5:f4de114c31c3 | 160 | |
embeddedartists | 5:f4de114c31c3 | 161 | // cause a repaint |
embeddedartists | 5:f4de114c31c3 | 162 | if (order[0] != NULL) { |
embeddedartists | 5:f4de114c31c3 | 163 | order[0]->activeData = NULL; |
embeddedartists | 5:f4de114c31c3 | 164 | |
embeddedartists | 5:f4de114c31c3 | 165 | // Very important that the signal is not sent while the lock is held |
embeddedartists | 5:f4de114c31c3 | 166 | // as it will cause the renderer thread be able to take it also |
embeddedartists | 5:f4de114c31c3 | 167 | setupMutex.unlock(); |
embeddedartists | 15:a68bb30ab95e | 168 | osSignalSet(threadId, layer->signalId); |
embeddedartists | 5:f4de114c31c3 | 169 | return; |
embeddedartists | 5:f4de114c31c3 | 170 | } else { |
embeddedartists | 5:f4de114c31c3 | 171 | // no longer anything to show, clear back buffers |
embeddedartists | 5:f4de114c31c3 | 172 | memset(ImageBackBuffer[0], 0xff, screenBytes); |
embeddedartists | 5:f4de114c31c3 | 173 | memset(ImageBackBuffer[1], 0xff, screenBytes); |
embeddedartists | 5:f4de114c31c3 | 174 | } |
embeddedartists | 5:f4de114c31c3 | 175 | |
embeddedartists | 5:f4de114c31c3 | 176 | break; |
embeddedartists | 5:f4de114c31c3 | 177 | } |
embeddedartists | 5:f4de114c31c3 | 178 | } |
embeddedartists | 5:f4de114c31c3 | 179 | } |
embeddedartists | 5:f4de114c31c3 | 180 | setupMutex.unlock(); |
embeddedartists | 5:f4de114c31c3 | 181 | } |
embeddedartists | 5:f4de114c31c3 | 182 | |
embeddedartists | 5:f4de114c31c3 | 183 | void Renderer::setFramebuffer(uint32_t handle, const uint16_t* data) |
embeddedartists | 5:f4de114c31c3 | 184 | { |
embeddedartists | 5:f4de114c31c3 | 185 | layerinfo_t* layer = (layerinfo_t*)handle; |
embeddedartists | 5:f4de114c31c3 | 186 | |
embeddedartists | 5:f4de114c31c3 | 187 | // make sure that the render thread is not using the data when |
embeddedartists | 5:f4de114c31c3 | 188 | // we change it |
embeddedartists | 5:f4de114c31c3 | 189 | layer->lock->lock(); |
embeddedartists | 5:f4de114c31c3 | 190 | layer->newData = data; |
embeddedartists | 5:f4de114c31c3 | 191 | layer->activeData = NULL; |
embeddedartists | 5:f4de114c31c3 | 192 | layer->lock->unlock(); |
embeddedartists | 5:f4de114c31c3 | 193 | |
embeddedartists | 5:f4de114c31c3 | 194 | // notify the renderer that there is new data for our layer |
embeddedartists | 15:a68bb30ab95e | 195 | osSignalSet(threadId, layer->signalId); |
embeddedartists | 5:f4de114c31c3 | 196 | } |
embeddedartists | 5:f4de114c31c3 | 197 | |
embeddedartists | 5:f4de114c31c3 | 198 | void Renderer::render() |
embeddedartists | 5:f4de114c31c3 | 199 | { |
embeddedartists | 15:a68bb30ab95e | 200 | //save this thread's ID so that it may be signalled from |
embeddedartists | 15:a68bb30ab95e | 201 | //unregisterUser() and setFramebuffer() |
embeddedartists | 15:a68bb30ab95e | 202 | threadId = Thread::gettid(); |
embeddedartists | 15:a68bb30ab95e | 203 | |
embeddedartists | 5:f4de114c31c3 | 204 | int mask = 1;//(1<<MaxNumLayers) - 1; |
embeddedartists | 5:f4de114c31c3 | 205 | while(true) |
embeddedartists | 5:f4de114c31c3 | 206 | { |
embeddedartists | 5:f4de114c31c3 | 207 | osEvent ev = Thread::signal_wait(mask); |
embeddedartists | 5:f4de114c31c3 | 208 | if (ev.status == osEventSignal) { |
embeddedartists | 5:f4de114c31c3 | 209 | setupMutex.lock(); |
embeddedartists | 5:f4de114c31c3 | 210 | for (int i = 0; i < numRegisteredLayers; i++) { |
embeddedartists | 5:f4de114c31c3 | 211 | if (order[i]->activeData != order[i]->newData) { |
embeddedartists | 5:f4de114c31c3 | 212 | //if (order[i]->signalId & ev.value.signals) { |
embeddedartists | 5:f4de114c31c3 | 213 | |
embeddedartists | 5:f4de114c31c3 | 214 | int n = (activeBackBuffer + 1) & 1; |
embeddedartists | 5:f4de114c31c3 | 215 | |
embeddedartists | 5:f4de114c31c3 | 216 | // if (i == 0) { |
embeddedartists | 5:f4de114c31c3 | 217 | // // TEMPORARY |
embeddedartists | 5:f4de114c31c3 | 218 | // board->setFrameBuffer((uint32_t)ImageBackBuffer[n]); |
embeddedartists | 5:f4de114c31c3 | 219 | // if (order[i]->activeData != NULL && order[i]->newData != NULL) { |
embeddedartists | 5:f4de114c31c3 | 220 | // for (int y = 0; y < order[i]->clippedHeight; y++) { |
embeddedartists | 5:f4de114c31c3 | 221 | // for (int x = 0; x < order[i]->width; x++) { |
embeddedartists | 5:f4de114c31c3 | 222 | // if (order[i]->activeData[y*order[i]->width+x] != order[i]->newData[y*order[i]->width+x]) { |
embeddedartists | 5:f4de114c31c3 | 223 | // printf("Difference in x,y {%d,%d} active is 0x%04x, new is 0x%04x\n", x, y, |
embeddedartists | 5:f4de114c31c3 | 224 | // order[i]->activeData[y*order[i]->width+x], order[i]->newData[y*order[i]->width+x]); |
embeddedartists | 5:f4de114c31c3 | 225 | // } |
embeddedartists | 5:f4de114c31c3 | 226 | // } |
embeddedartists | 5:f4de114c31c3 | 227 | // } |
embeddedartists | 5:f4de114c31c3 | 228 | // } |
embeddedartists | 5:f4de114c31c3 | 229 | // } |
embeddedartists | 5:f4de114c31c3 | 230 | |
embeddedartists | 5:f4de114c31c3 | 231 | // Layer i have new data |
embeddedartists | 5:f4de114c31c3 | 232 | // redraw this layer and all on top of it |
embeddedartists | 5:f4de114c31c3 | 233 | for (int j = i; j < numRegisteredLayers; j++) { |
embeddedartists | 5:f4de114c31c3 | 234 | layerinfo_t* layer = order[j]; |
embeddedartists | 5:f4de114c31c3 | 235 | layer->lock->lock(); |
embeddedartists | 5:f4de114c31c3 | 236 | layer->activeData = layer->newData; |
embeddedartists | 5:f4de114c31c3 | 237 | memcpy(layer->tmp, layer->newData, layer->width*layer->clippedHeight*2); |
embeddedartists | 5:f4de114c31c3 | 238 | layer->lock->unlock(); |
embeddedartists | 5:f4de114c31c3 | 239 | if (layer->activeData != NULL) { |
embeddedartists | 5:f4de114c31c3 | 240 | if (layer->fullscreen) { |
embeddedartists | 5:f4de114c31c3 | 241 | memcpy(ImageBackBuffer[n], layer->tmp, screenBytes); |
embeddedartists | 5:f4de114c31c3 | 242 | } else { |
embeddedartists | 5:f4de114c31c3 | 243 | for (int y = 0; y < layer->clippedHeight; y++) { |
embeddedartists | 5:f4de114c31c3 | 244 | memcpy(ImageBackBuffer[n] + ((y + layer->y0) * screenWidth) + layer->x0, |
embeddedartists | 5:f4de114c31c3 | 245 | layer->tmp + (y * layer->width), |
embeddedartists | 5:f4de114c31c3 | 246 | (layer->x1 - layer->x0) * 2); |
embeddedartists | 5:f4de114c31c3 | 247 | } |
embeddedartists | 5:f4de114c31c3 | 248 | } |
embeddedartists | 5:f4de114c31c3 | 249 | } |
embeddedartists | 5:f4de114c31c3 | 250 | } |
embeddedartists | 5:f4de114c31c3 | 251 | |
embeddedartists | 5:f4de114c31c3 | 252 | //board->setFrameBuffer((uint32_t)ImageBackBuffer[n]); |
embeddedartists | 5:f4de114c31c3 | 253 | display->setFramebuffer(ImageBackBuffer[n]); |
embeddedartists | 5:f4de114c31c3 | 254 | if (i == (numRegisteredLayers - 1)) { |
embeddedartists | 5:f4de114c31c3 | 255 | // only top layer changed, no need to copy entire back buffer |
embeddedartists | 5:f4de114c31c3 | 256 | } else { |
embeddedartists | 5:f4de114c31c3 | 257 | // more layers exist on top so the back buffer must be updated |
embeddedartists | 5:f4de114c31c3 | 258 | memcpy(ImageBackBuffer[activeBackBuffer], ImageBackBuffer[n], screenBytes); |
embeddedartists | 5:f4de114c31c3 | 259 | } |
embeddedartists | 5:f4de114c31c3 | 260 | activeBackBuffer = n; |
embeddedartists | 5:f4de114c31c3 | 261 | break; |
embeddedartists | 5:f4de114c31c3 | 262 | } |
embeddedartists | 5:f4de114c31c3 | 263 | } |
embeddedartists | 5:f4de114c31c3 | 264 | setupMutex.unlock(); |
embeddedartists | 5:f4de114c31c3 | 265 | } |
embeddedartists | 5:f4de114c31c3 | 266 | } |
embeddedartists | 5:f4de114c31c3 | 267 | } |