3 * - By John Hodge (thePowersGang)
6 * - 2D command processing
10 #include <acess/devices/pty_cmds.h>
12 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y);
13 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H);
14 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data);
15 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data);
16 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data);
17 int VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data);
20 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y)
22 if( Term->Mode == PTYBUFFMT_TEXT )
24 tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term);
26 wrpos->Col = Y + (Term->Flags & VT_FLAG_ALTBUF ? 0 : Term->ViewTopRow);
27 VT_int_UpdateCursor(Term, 0);
31 Term->VideoCursorX = X;
32 Term->VideoCursorY = Y;
33 VT_int_UpdateCursor(Term, 1);
37 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H)
39 LOG("WxH = %ix%i", W, H);
42 if(W * H != Term->VideoCursor->W * Term->VideoCursor->H) {
43 free(Term->VideoCursor);
44 Term->VideoCursor = NULL;
47 if(!Term->VideoCursor) {
48 Term->VideoCursor = malloc(sizeof(*Term->VideoCursor) + W*H*sizeof(Uint32));
49 if(!Term->VideoCursor) {
50 Log_Error("VTerm", "Unable to allocate memory for cursor");
54 Term->VideoCursor->W = W;
55 Term->VideoCursor->H = H;
56 Term->VideoCursor->XOfs = 0;
57 Term->VideoCursor->YOfs = 0;
60 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data)
62 if( !Term->VideoCursor )
64 size_t limit = Term->VideoCursor->W * Term->VideoCursor->H * 4;
69 if( DataOfs + Length > limit )
70 Length = limit - DataOfs;
72 LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length);
73 memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length);
75 if(gpVT_CurTerm == Term)
76 VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor);
80 // --- 2D Command deserialising ---
81 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data)
83 struct ptycmd_setcursorpos cmd;
84 if( Length < sizeof(cmd) ) return 0;
85 memcpy(&cmd, Data, sizeof(cmd));
87 VT_int_SetCursorPos(Handle, cmd.x, cmd.y);
92 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data)
94 struct ptycmd_setcursorbmp cmd;
95 tVTerm *term = Handle;
99 if( Length < sizeof(cmd) ) return 0;
100 memcpy(&cmd, Data, sizeof(cmd));
101 VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h);
104 Data = (const char*)Data + ret;
108 ASSERTC(Offset, >=, sizeof(cmd));
112 ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
115 LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
116 if( ret + Offset >= term->Cmd2D.CurrentSize )
122 int VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data)
124 tVTerm *term = Handle;
125 struct ptycmd_senddata cmd;
130 if( Length < sizeof(cmd) )
132 memcpy(&cmd, Data, sizeof(cmd));
137 Data = (const char*)Data + ret;
139 term->Cmd2D.CmdInfo.Push.Offset = cmd.ofs*4;
142 ASSERTC(Offset, >=, sizeof(cmd));
146 size_t bytes = MIN(term->Width*term->Height*4 - term->Cmd2D.CmdInfo.Push.Offset, Length);
147 LOG("bytes = %i (0x%x), Length = %i", bytes, bytes, Length);
149 VT_int_PutFBData(term, term->Cmd2D.CmdInfo.Push.Offset, bytes, Data );
150 term->Cmd2D.CmdInfo.Push.Offset += bytes;
153 LOG("bytes(%i) ==? 0 || ret(%i) + Offset(%i) ==? %i",
154 bytes, ret, Offset, term->Cmd2D.CurrentSize);
155 if( bytes == 0 || ret + Offset >= term->Cmd2D.CurrentSize )
162 // > 0: Command complete
163 // = 0: Not enough data to start
164 // < 0: Ate -n bytes, still need more
165 typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data);
166 tVT_2DCmdHandler gVT_2DCmdHandlers[] = {
167 [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
168 [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
169 [PTY2D_CMD_SEND] = VT_int_2DCmd_SendData,
171 const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
173 void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
175 const uint8_t *bdata = Data;
176 tVTerm *term = Handle;
178 LOG("Length = 0x%x", Length);
179 // If a command didn't consume all the data it said it would, we have to clean up
181 if( term->Cmd2D.PreEat )
183 size_t nom = MIN(term->Cmd2D.PreEat, Length);
186 LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat);
187 term->Cmd2D.PreEat -= nom;
192 const int cachesize = sizeof(term->Cmd2D.Cache);
196 // Check for command resume
197 if( term->Cmd2D.Current )
199 LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length);
200 dataptr = (void*)bdata;
204 // else begin a new command
207 // If the new data would fit in the cache, or the cache is already populated
209 // - The cache should fit the header for every command, so all good
210 if( Length < cachesize || term->Cmd2D.CachePos != 0 )
212 adjust = term->Cmd2D.CachePos;
213 size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length);
214 memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes);
215 term->Cmd2D.CachePos += newbytes;
216 dataptr = (void*)term->Cmd2D.Cache;
217 len = term->Cmd2D.CachePos;
221 dataptr = (void*)bdata;
225 const struct ptycmd_header *hdr = dataptr;
227 // If there's not enough for the common header, wait for more
228 if( len < sizeof(*hdr) )
234 term->Cmd2D.Offset = 0;
235 term->Cmd2D.Current = hdr->cmd;
236 term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
237 if( term->Cmd2D.CurrentSize == 0 ) {
238 Log_Warning("VTerm", "Command size too small (==0)");
239 term->Cmd2D.CurrentSize = 2;
241 LOG("Started %i with %s data",
242 term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
246 if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
248 Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
249 if( Length < term->Cmd2D.CurrentSize )
251 term->Cmd2D.CachePos = 0;
252 term->Cmd2D.Current = 0;
253 term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
257 const tVT_2DCmdHandler* handler = &gVT_2DCmdHandlers[term->Cmd2D.Current];
259 if( term->Cmd2D.Offset == 0 )
261 if( len < handler->HeaderLength ) {
264 rv = handler->Header(Handle, len, dataptr);
268 rv = hander->Body(Handle, term->Cmd2D.Offset, len, dataptr);
273 int rv = (*handler)(Handle, term->Cmd2D.Offset, len, dataptr);
274 LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
276 // If it returned 0 on the first call, it lacks space for the header
277 if( rv == 0 && term->Cmd2D.Offset == 0 )
279 ASSERT( term->Cmd2D.CachePos != cachesize );
280 // Clear current command because this command hasn't started yet
281 term->Cmd2D.Current = 0;
282 // Return, restart happens once all data is ready
286 // Consume the byte count returned (adjust is the number of bytes that were already cached)
287 size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
288 Length -= used_bytes;
290 term->Cmd2D.CachePos = 0;
291 // If a negative count was returned, more data is expected
293 ASSERT( -rv <= len );
295 term->Cmd2D.Offset += -rv;
299 term->Cmd2D.Current = 0;
301 // Eat up any uneaten data
302 ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
303 if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
305 size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
306 LOG("Left %i bytes", diff);
307 term->Cmd2D.PreEat = diff;
310 LOG("Done (%i bytes left)", Length);