unsigned short int UbirchSIM800::HTTP_get(const char *url, unsigned long int &length, STREAM &file) { unsigned short int status = HTTP_get(url, length); PRINT("HTTP STATUS: "); DEBUGLN(status); PRINT("FILE LENGTH: "); DEBUGLN(length); if (length == 0) return status; char *buffer = (char *) malloc(SIM800_BUFSIZE); uint32_t pos = 0; do { size_t r = HTTP_read(buffer, pos, SIM800_BUFSIZE); #if !defined(NDEBUG) && defined(DEBUG_PROGRESS) if ((pos % 10240) == 0) { PRINT(" "); DEBUGLN(pos); } else if (pos % (1024) == 0) { PRINT("<"); } #endif pos += r; file.write(buffer, r); } while (pos < length); free(buffer); PRINTLN(""); return status; }
boolean URCQueue<i>::Enqueue(const char *pURCText) { if(FCount >= i) { DEBUG_P(PSTR("** URC Queue is Full"LB)); return false; } DEBUG_P(PSTR("Queuing URC --> ")); DEBUGLN(pURCText); char *item = strdup(pURCText); if(item) { FURCQueue[FCount] = item; FCount++; return true; } else { DEBUG_P(PSTR("**URC Not enough memory"LB)); return false; } };
ModemGSM::EStandardAnswer ModemGSM::WaitAnswer(unsigned int pTimeoutMS, boolean pHandleURC) { //DEBUG_P("WaitAnswer --> "); for(;;) { if(Readln(pTimeoutMS, false) == TIMEOUT) { DEBUG_P(PSTR("** TIMEOUT"LB)); return saTimeout; } //DEBUGLN(FRXBuff); if(strcmp_P(FRXBuff,PSTR("OK")) == 0) { //DEBUGLN_P("OK"); return saOk; } else if( (strcmp_P(FRXBuff,PSTR("ERROR")) == 0) || (strncmp_P(FRXBuff,PSTR("+CME ERROR:"), 11) == 0) || (strncmp_P(FRXBuff,PSTR("+CMS ERROR:"), 11) == 0)) { DEBUG_P(PSTR("** ")); DEBUGLN(FRXBuff); return saError; } else if(pHandleURC) HandleURC(); else return saUnknown; } }
boolean ModemGSM::RegisterNumberInPB(char *pName, char *pNumber) { DEBUG_P(PSTR("Writing PB entry --> ")); if(pName) { DEBUG(pName); DEBUG_P(PSTR(" : ")); } DEBUGLN(pNumber); if(pName) { SendCommand(PSTR("AT+CPBW=,\"%s\",,\"%s\""), pNumber, pName); } else SendCommand(PSTR("AT+CPBW=,\"%s\""), pNumber); boolean res = WaitAnswer(5000, true) == saOk; //Wait a while. It seems that issuing a command immediately after this the modem hangs delay(2000); return res; }
void UbirchSIM800::print(uint32_t s) { #ifdef DEBUG_AT PRINT("+++ "); DEBUGLN(s); #endif _serial.print(s); }
boolean URCQueue<i>::Dequeue(char *pURCText, size_t pURCTextSize) { if(FCount == 0) { DEBUG_P(PSTR("** URC Queue is Empty"LB)); return false; } DEBUG_P(PSTR("Dequeuing URC --> ")); if(pURCText) { strncpy(pURCText, FURCQueue[0], pURCTextSize - 1); pURCText[pURCTextSize - 1] = '\0'; DEBUGLN(FURCQueue[0]); } else DEBUG_P(PSTR("Value Discarded"LB)); Dispose(0); FCount--; memmove(FURCQueue, FURCQueue+1, sizeof(char *) * FCount); return true; };
unsigned short int UbirchSIM800::HTTP_post(const char *url, unsigned long int &length, STREAM &file, uint32_t size) { expect_AT_OK(F("+HTTPTERM")); delay(100); if (!expect_AT_OK(F("+HTTPINIT"))) return 1000; if (!expect_AT_OK(F("+HTTPPARA=\"CID\",1"))) return 1101; if (!expect_AT_OK(F("+HTTPPARA=\"UA\",\"UBIRCH#1\""))) return 1102; if (!expect_AT_OK(F("+HTTPPARA=\"REDIR\",1"))) return 1103; println_param("AT+HTTPPARA=\"URL\"", url); if (!expect_OK()) return 1110; print(F("AT+HTTPDATA=")); print(size); print(F(",")); println((uint32_t) 120000); if (!expect(F("DOWNLOAD"))) return 0; uint8_t *buffer = (uint8_t *) malloc(SIM800_BUFSIZE); uint32_t pos = 0, r = 0; do { for (r = 0; r < SIM800_BUFSIZE; r++) { int c = file.read(); if (c == -1) break; _serial.write((uint8_t) c); } if (r < SIM800_BUFSIZE) { #if !defined(NDEBUG) && defined(DEBUG_PROGRESS) PRINTLN("EOF"); #endif break; } #ifndef NDEBUG if ((pos % 10240) == 0) { PRINT(" "); DEBUGLN(pos); } else if (pos % (1024) == 0) { PRINT(">"); } #endif pos += r; } while (r == SIM800_BUFSIZE); free(buffer); PRINTLN(""); if (!expect_OK(5000)) return 1005; if (!expect_AT_OK(F("+HTTPACTION=1"))) return 1004; // wait for the action to be completed, give it 5s for each try uint16_t status; while (!expect_scan(F("+HTTPACTION: 1,%hu,%lu"), &status, &length, 5000)); return status; }
bool UbirchSIM800::status() { println(F("AT+CIPSTATUS=0")); char status[SIM800_BUFSIZE]; expect_scan(F("+CIPSTATUS: %s"), status); DEBUGLN(status); if (!expect_OK()) return false; return strcmp_P(status, PSTR("CONNECTED")) < 0; }
size_t UbirchSIM800::HTTP_read(char *buffer, uint32_t start, size_t length) { print(F("AT+HTTPREAD=")); print(start); print(F(",")); println((uint32_t) length); unsigned long int available; expect_scan(F("+HTTPREAD: %lu"), &available); #ifdef DEBUG_PACKETS PRINT("~~~ PACKET: "); DEBUGLN(available); #endif size_t idx = read(buffer, (size_t) available); if (!expect_OK()) return 0; #ifdef DEBUG_PACKETS PRINT("~~~ DONE: "); DEBUGLN(idx); #endif return idx; }
boolean ModemGSM::WriteSMS(const char *pDestPhoneNumber, const char *pBody,int *pIndex) { boolean res = false; DEBUG_P(PSTR("Writing SMS --> %s : "), pDestPhoneNumber); DEBUGLN(pBody); if(pIndex) *pIndex = 0; SendCommand(PSTR("AT+CMGW=\"%s\""), pDestPhoneNumber); DiscardPrompt(1500); //Discard modem prompt FSerial->print(pBody); delay(500); FSerial->print(0x1A,BYTE); //CTRL+Z End of Message for(;;) { //AT+CMGW can take a long time to answer switch(WaitAnswer(20000)) { case saOk: return res; case saError: case saTimeout: return false; case saUnknown: { int idx; if(sscanf_P(FRXBuff, PSTR("+CMGW: %d"), &idx) == 1) { DEBUG_P(PSTR("SMS Written at index -> %d"LB), idx); res = true; if(pIndex) *pIndex = idx; } else HandleURC(); } } } }
boolean ModemGSM::ReadSMSAtIndex(int pIndex, TSMSPtr pSMS) { boolean hasEntry = false; DEBUG_P(PSTR("Reading SMS entry at --> %d"LB), pIndex); SendCommand(PSTR("AT+CMGR=%d"), pIndex); for(;;) { switch(WaitAnswer(5000)) { case saOk: return hasEntry; case saError: case saTimeout: return false; case saUnknown: { int idx; if(sscanf_P(FRXBuff, PSTR("+CMGR: \"%*[^\"]\",\"%20[^\"]\""), pSMS->phone) == 1) { DEBUG_P(PSTR(" SMS Number -> %s"LB), pSMS->phone); if(Readln(500, true) != 0) { DEBUG_P(PSTR(" SMS Text -> ")); DEBUGLN(FRXBuff); strncpy(pSMS->body, FRXBuff, sizeof(pSMS->body) - 1); pSMS->body[sizeof(pSMS->body) - 1] = '\0'; hasEntry = true; } else { DEBUG_P(PSTR("** Timeout reading SMS text"LB)); return false; } } else HandleURC(); } } } }
boolean ModemGSM::GetPBEntryByName(const char *pName, char *pNumber, int *pIndex) { boolean hasEntry = false; DEBUG_P(PSTR("Reading PB entry --> %s"LB), pName); SendCommand(PSTR("AT+CPBF=\"%s\""), pName); for(;;) { switch(WaitAnswer(10000)) { case saOk: return hasEntry; case saError: case saTimeout: return false; case saUnknown: { int idx; //Stop on first entry. if(!hasEntry && (sscanf_P(FRXBuff,PSTR("+CPBF: %d,\"%20[^\"]\""), &idx, pNumber) == 2)) { DEBUGLN(pNumber); hasEntry = true; if(pIndex) *pIndex = idx; } else HandleURC(); } } } }
bool UbirchSIM800::is_urc(const char *line, size_t len) { urc_status = 0xff; for (uint8_t i = 0; i < 17; i++) { #ifdef __AVR__ const char *urc = (const char *) pgm_read_word(&(_urc_messages[i])); #else const char *urc = _urc_messages[i]; #endif size_t urc_len = strlen(urc); if (len >= urc_len && !strncmp(urc, line, urc_len)) { #ifdef DEBUG_URC PRINT("!!! SIM800 URC("); DEBUG(i); PRINT(") "); DEBUGLN(urc); #endif urc_status = i; return true; } } return false; }
int ModemGSM::Dispatch() { int res = 0; int level; int ind; static int state=0; EvalNetworkLedStatus(); #ifdef REGISTRATION_DELAYED if(FNetworkRegDelayActive && FNetworkRegDelayTS.IsExpired()) { DEBUG_P(PSTR("Network Registration Delay Expired --> Now Registered To Network"LB)); FNetworkRegDelayActive = false; FRegisteredToNetwork = true; } #endif if(FLastKeepAliveTS.IsExpired()) { #if SIMULATION if(FPBReady) { int idx; char temp[30]; // switch(state % 3) //repeat commands switch(state) { case 0: { DEBUG_P(PSTR("---- Posting Fake SMS"LB)); WriteSMS("+390000000000", "ON 0000,22", &idx); sprintf_P(temp, PSTR("+CMTI: \"SM\",%d"), idx); break; } case 1: { DEBUG_P(PSTR("---- Posting Fake SMS"LB)); WriteSMS("+390000000000", "ON 0000,22", &idx); sprintf_P(temp, PSTR("+CMTI: \"SM\",%d"), idx); break; } default: { temp[0] = 0; if(!SendKeepAlive()) { FKeepAliveFailedCount++; //if the modem is not answering try the hard way ... if(FKeepAliveFailedCount > 5) { //Try to power off the modem SendCommand("AT+CPWROFF"); delay(1000); //Signal Error condition FError = true; return res; } } else { FError = false; FKeepAliveFailedCount = 0; } } } state++; if(temp[0]) { FURCQueue.Enqueue(temp); DEBUG_P(PSTR("---- Posted Fake SMS"LB)); } } else #endif if(!SendKeepAlive()) { FKeepAliveFailedCount++; //if the modem is not answering try the hard way ... if(FKeepAliveFailedCount > 5) { //Try to power off the modem SendCommand("AT+CPWROFF"); delay(1000); //Signal Error condition FError = true; return res; } } else { FError = false; FKeepAliveFailedCount = 0; } FLastKeepAliveTS.Reset(); }; int idx; //Check for Queued URC or Data from Modem SerialLine if((FURCQueue.Count() ? FURCQueue.Dequeue(FRXBuff, sizeof(FRXBuff)) : false) || (Readln(100, false) != TIMEOUT)) { if(sscanf_P(FRXBuff, PSTR("+CMTI: \"%*[^\"]\",%d"), &idx) == 1) { DEBUG_P(PSTR("SMS Received at -> %d"LB), idx); //Save SMS position in SM Memory, the SMS is stored by the Modem FSMSInQueue.Enqueue(idx); } else if((sscanf_P(FRXBuff,PSTR("+CMGS: %d"), &level) == 1) || (sscanf_P(FRXBuff,PSTR("+CMSS: %d"), &level) == 1)) { DEBUG_P(PSTR("Last Message Sent Successfully"LB)); } else if(sscanf_P(FRXBuff,PSTR("+CIEV: %d,%d"), &ind, &level) == 2) { if(ind == 2) { if((level >= 1) && (level <= 5)) { FSignalLevel = level; DEBUG_P(PSTR("Signal Strength --> %d"LB), level); } else { FSignalLevel = UNKNOWN_LEVEL; DEBUG_P(PSTR("**BAD Signal Strength --> %d"LB), level); } } } else if(sscanf_P(FRXBuff,PSTR("+CREG: %d"), &level) == 1) { if((level == 1) || (level == 5)) { #ifdef REGISTRATION_DELAYED DEBUG_P(PSTR("Registered to Network Indication --> Starting Delay"LB)); FNetworkRegDelayActive = true; //Wait for a while to be sure that SMS will work FNetworkRegDelayTS.Reset(); #else FRegisteredToNetwork = true; DEBUGLN_P(PSTR("Registered to Network"LB)); #endif } else { DEBUG_P(PSTR("NOT Registered to Network"LB)); FRegisteredToNetwork = false; #ifdef REGISTRATION_DELAYED FNetworkRegDelayActive = false; #endif } FLastBlinkTS.Reset(); EvalNetworkLedStatus(); } else if(strncmp(FRXBuff,"+XDRVI: ", 8) == 0) { resetCount++; DEBUG_P(PSTR("Module RESET"LB)); DiscardSerialInput(5000); InnerSetup(); } else if(strcmp_P(FRXBuff,PSTR("+PBREADY")) == 0) { FPBReady = true; for(int i = 0; i < 10; i++) if(ClearSMSMemory()) break; else { delay(1000); DEBUG_P(PSTR("Retrying .... "LB)); } FLastKeepAliveTS.Reset(); } else { DEBUG_P(PSTR("** Unhandled -> ")); DEBUGLN(FRXBuff); } } //Do not fire SMS retries if the network is not available if((FSMSOutQueue.Count() && FRegisteredToNetwork) && !(FSMSResendPending && !FSMSResendTS.IsExpired())) { int idx; FSMSOutQueue.Peek(&idx); if(SendSMSAtIndex(idx)) { SMSDequeue(qOut, NULL); FSMSResendPending = false; } else { //A retry failed ? if(FSMSResendPending) { //some other retry available ? if(FSMSRetry) { FSMSRetry--; FSMSResendTS.Reset(); DEBUG_P(PSTR("Retrying SMS Send. Retry Count --> %d"LB), (int)FSMSRetry); } else { //discard SMS FSMSResendPending = false; FSMSOutQueue.Dequeue(NULL); DEBUG_P(PSTR("** Too Many Retries SMS Send Aborted"LB)); } } else { //Start a delay and retry sequence FSMSRetry = SMS_RETRY_COUNT; FSMSResendPending = true; FSMSResendTS.Reset(); DEBUG_P(PSTR("Retrying SMS Send. Retry Count --> %d"LB), (int)FSMSRetry); } } } return res; }
/*EDU US*/ void rgb_lcd::effectiveNewWrite(String newString){ //--- On crée des variables locales int8_t userCol; // Utilisée pour sauvegarder la position du curseur utilisateur //--- On sauvegarde la position du curseur de l'utilisateur userCol = m_curentCol; //--- On récupère la ligne courante DEBUG2("La ligne courante est : ", m_curentRow); //--- On récupère la colonne courante DEBUG2("La colonne courante est : ", m_curentCol); //--- On récupère la dernière taille max à partir de temp int8_t maxLength=m_maxLength[m_curentCol][m_curentRow]; DEBUG2("La derniere taille max enregistree est : ", maxLength); //--- Détermination de la taille du nbr reçu int8_t newMaxLength=newString.length(); DEBUG2("La nouvelle taille max est : ", newMaxLength); //--- On compare et enregistre la taille max int8_t curentLength; if(newMaxLength>maxLength){ // Il faut sauvegarder la nouvelle valeurs m_maxLength[m_curentCol][m_curentRow]=newMaxLength; // Sauvegarde dans une variable pratique curentLength=newMaxLength; DEBUG2("On enregistre la nouvelle taille max avec : ", m_maxLength[m_curentCol][m_curentRow]); } else { // Sauvegarde dans une variable pratique curentLength=maxLength; DEBUG2("On garde l ancienne valeur de taille max : ", m_maxLength[m_curentCol][m_curentRow]); } //--- TEMP: On construit une chaine à partir de la ligne courante et de la position du curseur //-- On construit 1 chaîne vide char tempRow[16]; //-- On remplit la chaine avec des valeurs par défaut for(int8_t k=0;k<NBR_COLS;k++){ tempRow[k]='-'; } //--- TEMP: On ajoute le nombre reçu à la ligne courante et à l'endroit du curseur //-- On complète la chaîne newString pour qu'elle ait la longueur max constatée //-- La taille de la chaîne doit être de curentLength //-- On compare la longeur réelle et la longeur souhaitée int8_t diffLength = maxLength-newMaxLength; DEBUG2("La difference de longeur (pour cette position) est de :", diffLength); //-- On teste si le nombre à diminué de longueur if(diffLength>0){ //- Il faut alors complèter la chaîne car elle est trop courte for(int8_t i=0;i<=diffLength;i++){ //- On ajoute un x à la chaîne newString+=' '; } DEBUG2("Des 0 ont été ajoutés. La chaîne vaut maitenant : ", newString); } //--- On enregistre la nouvelle chaîne temp. On commence la boucle à l'endroit du curseur for(int8_t i=0;i<curentLength;i++){ //-Ecriture du nouveau mot dans la ligne courente du tableau temp tempRow[m_curentCol+i]=newString[i]; } //-- Affichage de la ligne TEMP => Serial DEBUG_TAB("La chaine temp vaut maintenant : ",tempRow,0,16); //for(int8_t i=0;i<16;i++){Serial.print(tempRow[i]);} Serial.println(" "); //--- Affichage de memory => Serial DEBUG_TAB2("MEMORY (avant modifications) contient : ", m_memory,0,15,0,1); //for(int8_t i=0;i<16;i++){Serial.print(m_memory[i][0]);} Serial.println(" "); //for(int8_t i=0;i<16;i++){Serial.print(m_memory[i][1]);} Serial.println(" "); //--- On va comparer la ligne temp avec m_memory uniquement sur la plage taille max DEBUG("Debut comparaison entre la ligne temp et m_memory - "); DEBUGLN("La comparaison se fait case par case sur la ligne courante"); // INFOS : Debut de la boucle=position curseur (m_curentCol) // INFOS : Fin de la boucle = position curseur+largeur max //-- On calcule le début de la boucle int8_t startTest = m_curentCol; //-- On calcule la fin de la boucle int8_t endTest = startTest+curentLength; //-- Rappel colone utilisateur DEBUG2("Colonne utilisateur : ", userCol); //-- On lance la comparaison sur la plage active for(int8_t c=startTest;c<endTest;c++){ //-- Comparaison case par case if(tempRow[c]!=m_memory[c][m_curentRow]){ DEBUG2("Case : ", c); //Serial.print("Case : "); Serial.print(c); DEBUG2(" : ", tempRow[c]); //Serial.print(" : "); Serial.print(tempRow[c]); DEBUG2(" different de : ", m_memory[c][m_curentRow]); //Serial.print(" different de : "); Serial.print(m_memory[c][m_curentRow]); DEBUG(" => Requete I2C necessaire ! "); //Serial.print(" => Requete I2C necessaire ! "); //-- On enregistre la nouvelle valeur dans m_memory m_memory[c][m_curentRow]=tempRow[c]; //-- On se rappelle qu'écire déplace le curseur //-- On envoit une reqête I2C //-On place le curseur à l'endroit de la modification setCursorOn(m_curentRow,c); DEBUG2("Curseur place en : ",c); // >>> EFECTIVE WRITE ! DEBUG2("Ecriture I2C de : ", tempRow[c]); write(tempRow[c]); } else{ DEBUG2("Case : ", c); DEBUG2(" : ", tempRow[c]); DEBUG2(" egale a : ", m_memory[m_curentRow][c]); } } //-- On replace le curseur après la fin du mot courant //- On calcule la nouvelle position souhaitée pour le curseur int8_t newPos; newPos = userCol + curentLength; setCursorOn(m_curentRow, newPos); // setCursor change automatiquement la position courante //--- Affichage de memory => Serial DEBUG_TAB2("MEMORY (apres modifications) contient : ", m_memory,0,15,0,1); }
// // Copied largely unchanged from Marlin // void Device_Heater::DoPidAutotune(uint8_t device_number, float temp, int ncycles) { float input = 0.0; int cycles = 0; bool heating = true; unsigned long temp_millis = millis(); unsigned long t1=temp_millis; unsigned long t2=temp_millis; long t_high = 0; long t_low = 0; long bias, d; float Ku, Tu; float Kp, Ki, Kd; float max = 0; float min = 10000; uint8_t p; uint8_t i; extern volatile bool temp_meas_ready; DEBUGLNPGM("PID Autotune start"); // switch off all heaters during auto-tune for (i=0; i<Device_Heater::GetNumDevices(); i++) { if (Device_Heater::IsInUse(i)) Device_Heater::SetHeaterPower(&heater_info_array[device_number], 0); } HeaterInfo *heater_info = &heater_info_array[device_number]; bias = d = p = heater_info->power_on_level; SetHeaterPower(heater_info, p); for(;;) { if(temp_meas_ready == true) { // temp sample ready Device_TemperatureSensor::UpdateTemperatureSensors(); input = Device_Heater::ReadCurrentTemperature(device_number); max=max(max,input); min=min(min,input); if(heating == true && input > temp) { if(millis() - t2 > 5000) { heating=false; p = bias - d; SetHeaterPower(heater_info, p); t1=millis(); t_high=t1 - t2; max=temp; } } if(heating == false && input < temp) { if(millis() - t1 > 5000) { heating=true; t2=millis(); t_low=t2 - t1; if(cycles > 0) { bias += (d*(t_high - t_low))/(t_low + t_high); bias = constrain(bias, 20 ,heater_info->power_on_level-20); if (bias > heater_info->power_on_level/2) d = heater_info->power_on_level - 1 - bias; else d = bias; DEBUGPGM(" bias: "); DEBUG_F(bias, DEC); DEBUGPGM(" d: "); DEBUG_F(d, DEC); DEBUGPGM(" min: "); DEBUG(min); DEBUGPGM(" max: "); DEBUGLN(max); if(cycles > 2) { Ku = (4.0*d)/(3.14159*(max-min)/2.0); Tu = ((float)(t_low + t_high)/1000.0); DEBUGPGM(" Ku: "); DEBUG(Ku); DEBUGPGM(" Tu: "); DEBUGLN(Tu); Kp = 0.6*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/8; DEBUGLNPGM(" Clasic PID "); DEBUGPGM(" Kp: "); DEBUGLN(Kp); DEBUGPGM(" Ki: "); DEBUGLN(Ki); DEBUGPGM(" Kd: "); DEBUGLN(Kd); /* Kp = 0.33*Ku; Ki = Kp/Tu; Kd = Kp*Tu/3; DEBUGLNPGM(" Some overshoot ") DEBUGPGM(" Kp: "); DEBUGLN(Kp); DEBUGPGM(" Ki: "); DEBUGLN(Ki); DEBUGPGM(" Kd: "); DEBUGLN(Kd); Kp = 0.2*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/3; DEBUGLNPGM(" No overshoot ") DEBUGPGM(" Kp: "); DEBUGLN(Kp); DEBUGPGM(" Ki: "); DEBUGLN(Ki); DEBUGPGM(" Kd: "); DEBUGLN(Kd); */ } } p = bias + d; SetHeaterPower(heater_info, p); cycles++; min=temp; } } } if(input > (temp + 20)) { ERRORLNPGM("PID Autotune failed! Temperature too high"); return; } if(millis() - temp_millis > 2000) { DEBUGLNPGM("ok T:"); DEBUG(input); DEBUGPGM(" @:"); DEBUGLN(p); temp_millis = millis(); } if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { ERRORLNPGM("PID Autotune failed! timeout"); return; } if(cycles > ncycles) { DEBUGLNPGM("PID Autotune finished! Record the last Kp, Ki and Kd constants"); return; } } }
TValue vm_interpret(AttoVM* vm, AttoBlock* block, int start, int argc) { DEBUGF("Interpret block: %d ops\n", block->code->size); int error = 0; TValue* max = (TValue*)(block->code->elements + start + block->code->size); TValue *pc_val = (TValue*)(block->code->elements + start); Instruction i = TV2INST(*pc_val); Stack *stack = &block->stack; const char* opcode_names[] = { OPCODE_NAMES }; const char* op_name = NULL; int x; for(x = 0; pc_val < max && !error; ++x) { op_name = i >= NUM_OPS ? "unknown" : opcode_names[i]; if(i >= NUM_OPS) { ERROR("bad opcode: %d", i); } DEBUGF("[%d]\t%s (%d)\n", x, op_name, i); switch(i) { case OP_NOP: DISPATCH; case OP_POP: EXPECT_ON_STACK(1); TValue v = pop(stack); valueDestroy(&v); DISPATCH; case OP_DUP: { EXPECT_ON_STACK(1); TValue v = pop(stack); push(stack, v); push(stack, v); DISPATCH; } case OP_SWAP: { EXPECT_ON_STACK(2); TValue f = pop(stack); TValue s = pop(stack); push(stack, f); push(stack, s); DISPATCH; } case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: { EXPECT_ON_STACK(2); TValue b = pop(stack); TValue a = pop(stack); TValue res = MathOp(i, a, b); push(stack, res); DISPATCH; } case OP_OR: case OP_AND: case OP_XOR: { EXPECT_ON_STACK(2); TValue b = pop(stack); TValue a = pop(stack); TValue res = BitwiseOp(i, a, b); push(stack, res); DISPATCH; } case OP_NOT: { EXPECT_ON_STACK(1); TValue a = pop(stack); push(stack, createNumber(~(long)TV2NUM(a))); DISPATCH; } case OP_EQ: case OP_LT: case OP_GT: case OP_LTE: case OP_GTE: case OP_CMP: { EXPECT_ON_STACK(2); TValue b = pop(stack); TValue a = pop(stack); TValue res = ComparisonOp(i, a, b); push(stack, res); DISPATCH; } case OP_IF: { EXPECT_ON_STACK(1); TValue t = pop(stack); if(boolValue(t)) { NEXTINST; } DISPATCH; } case OP_JMP: { EXPECT_ON_STACK(1); long jmp = (long)TV2NUM(pop(stack)); if(jmp + pc_val >= max || jmp + (long)pc_val < 0) { ERROR("Invalid jump: %ld", jmp); } pc_val += jmp; DISPATCH; } case OP_PUSHCONST: { int index = TV2INST(*++pc_val); if(index >= (int)block->k->size) { ERROR("Constant index out of bounds: %d", index); } TValue k = getIndex(block->k, index); push(stack, k); DISPATCH; } case OP_PUSHVAR: { int index = TV2INST(*++pc_val); if(index < 0 || index >= block->sizev) { ERROR("Variable index out of bounds: %d", index); } DEBUGF("PUSHVAR, index %d, value >> %s\n", index, TValue_to_string(block->vars[index])); TValue var = block->vars[index]; var.value.var.index = index; block->vars[index] = var; push(stack, var); DISPATCH; } case OP_SETVAR: { EXPECT_ON_STACK(2); TValue var = pop(stack); if(var.type != TYPE_VAR) { ERROR("Expected a var, but got %s", TValue_type_to_string(var)); } int index = var.value.var.index; TValue *val = malloc(sizeof(TValue)); *val = pop(stack); block->vars[index] = createVar(val); DEBUGF("SETVAR, index %d, value >> %s\n", index, TValue_to_string(block->vars[index])); DISPATCH; } case OP_VALUEVAR: { EXPECT_ON_STACK(1); TValue var = pop(stack); if(var.type != TYPE_VAR) { ERROR("Expected a var, but got %s", TValue_type_to_string(var)); } Value val = *var.value.var.value; AttoType type = var.value.var.type; TValue t; t.value = val; t.type = type; push(stack, t); DISPATCH; } case OP_BOOLVALUE: { EXPECT_ON_STACK(1); TValue tos = pop(stack); int bool = boolValue(tos); valueDestroy(&tos); push(stack, createBool(bool)); DISPATCH; } case OP_CONCAT: { EXPECT_ON_STACK(2); TValue top = pop(stack); TValue sec = pop(stack); if(!(top.type == TYPE_STRING && sec.type == TYPE_STRING)) { ERROR("Expected two string values, but got %s and %s", TValue_type_to_string(sec), TValue_type_to_string(top)); } char *top_s = TV2STR(top); char *sec_s = TV2STR(sec); char *str = malloc(strlen(top_s) + strlen(sec_s)); strcpy(str, sec_s); strcat(str, top_s); valueDestroy(&top); valueDestroy(&sec); push(stack, createString(str, strlen(str), 0)); free(str); DISPATCH; } case OP_PRINT: { EXPECT_ON_STACK(1); TValue v = pop(stack); char *str = TValue_to_string(v); printf("%s", str); if(v.type == TYPE_NUMBER) free(str); valueDestroy(&v); DISPATCH; } case OP_READLINE: { char *buf = malloc(BUFSIZ); memset(buf, '\0', BUFSIZ); if(fgets(buf, BUFSIZ, stdin) ) { char *nl = strchr(buf, '\n'); if(nl) { *nl = '\0'; } } unsigned len = strlen(buf) + 1; push(stack, createString(buf, len, 0)); free(buf); DISPATCH; } case OP_DUMPSTACK: print_stack(*stack); DISPATCH; case OP_CLEARSTACK: { Stack s = StackNew(); StackDestroy(&block->stack); *stack = s; DISPATCH; } case OP_CALL: { EXPECT_ON_STACK(2); TValue fcn = pop(stack); TValue num = pop(stack); // FIXME: this explodes when types aren't right :( if(fcn.type != TYPE_FUNCTION || num.type != TYPE_NUMBER) { ERROR("Expected function and numeric values, but got %s and %s", TValue_type_to_string(fcn), TValue_type_to_string(num)); } int nargs = (int)TV2NUM(num); EXPECT_ON_STACK(nargs); int j; for(j = 0; j < nargs; ++j) { TValue v = pop(stack); push(&fcn.value.function.b->stack, v); } TValue ret = vm_interpret(vm, fcn.value.function.b, 0, nargs); if(ret.type != TYPE_NULL) { push(stack, ret); } valueDestroy(&fcn); valueDestroy(&num); valueDestroy(&fcn); DISPATCH; } case OP_RETURN: { EXPECT_ON_STACK(1); TValue ret = pop(stack); DEBUGF("Finished block, returning with %s\n", TValue_to_string(ret)); return ret; DISPATCH; } default: ERROR("Unrecognized opcode: %d", i); } } DEBUGLN("Finished block"); return createNull(); }